home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / biosfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  64.9 KB  |  2,815 lines

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1993,1994 Atari Corporation.
  4. All rights reserved.
  5.  */
  6.  
  7. /* simple biosfs.c */
  8.  
  9. #include "mint.h"
  10.  
  11. extern struct kerinfo kernelinfo;    /* see main.c */
  12.  
  13. static long    ARGS_ON_STACK bios_root    P_((int drv, fcookie *fc));
  14. static long    ARGS_ON_STACK bios_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  15. static long    ARGS_ON_STACK bios_getxattr    P_((fcookie *fc, XATTR *xattr));
  16. static long    ARGS_ON_STACK bios_chattr    P_((fcookie *fc, int attrib));
  17. static long    ARGS_ON_STACK bios_chown    P_((fcookie *fc, int uid, int gid));
  18. static long    ARGS_ON_STACK bios_chmode    P_((fcookie *fc, unsigned mode));
  19. static long    ARGS_ON_STACK bios_rmdir    P_((fcookie *dir, const char *name));
  20. static long    ARGS_ON_STACK bios_remove    P_((fcookie *dir, const char *name));
  21. static long    ARGS_ON_STACK bios_getname    P_((fcookie *root, fcookie *dir, char *pathname, int size));
  22. static long    ARGS_ON_STACK bios_rename    P_((fcookie *olddir, char *oldname,
  23.                     fcookie *newdir, const char *newname));
  24. static long    ARGS_ON_STACK bios_opendir    P_((DIR *dirh, int flags));
  25. static long    ARGS_ON_STACK bios_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *fc));
  26. static long    ARGS_ON_STACK bios_rewinddir    P_((DIR *dirh));
  27. static long    ARGS_ON_STACK bios_closedir    P_((DIR *dirh));
  28. static long    ARGS_ON_STACK bios_pathconf    P_((fcookie *dir, int which));
  29. static long    ARGS_ON_STACK bios_dfree    P_((fcookie *dir, long *buf));
  30. static DEVDRV *    ARGS_ON_STACK bios_getdev    P_((fcookie *fc, long *devspecial));
  31. static long    ARGS_ON_STACK bios_fscntl    P_((fcookie *, const char *, int, long));
  32. static long    ARGS_ON_STACK bios_symlink    P_((fcookie *, const char *, const char *));
  33. static long    ARGS_ON_STACK bios_readlink    P_((fcookie *, char *, int));
  34.  
  35. static long    ARGS_ON_STACK bios_topen    P_((FILEPTR *f));
  36. static long    ARGS_ON_STACK bios_twrite    P_((FILEPTR *f, const char *buf, long bytes));
  37. static long    ARGS_ON_STACK bios_tread    P_((FILEPTR *f, char *buf, long bytes));
  38. static long    ARGS_ON_STACK bios_writeb    P_((FILEPTR *f, const char *buf, long bytes));
  39. static long    ARGS_ON_STACK bios_readb    P_((FILEPTR *f, char *buf, long bytes));
  40. static long    ARGS_ON_STACK bios_nwrite    P_((FILEPTR *f, const char *buf, long bytes));
  41. static long    ARGS_ON_STACK bios_nread    P_((FILEPTR *f, char *buf, long bytes));
  42. static long    ARGS_ON_STACK bios_ioctl    P_((FILEPTR *f, int mode, void *buf));
  43. static long    ARGS_ON_STACK bios_select    P_((FILEPTR *f, long p, int mode));
  44. static void    ARGS_ON_STACK bios_unselect    P_((FILEPTR *f, long p, int mode));
  45. static long    ARGS_ON_STACK bios_tseek    P_((FILEPTR *f, long where, int whence));
  46. static long    ARGS_ON_STACK bios_close    P_((FILEPTR *f, int pid));
  47.  
  48. long    ARGS_ON_STACK null_open    P_((FILEPTR *f));
  49. long    ARGS_ON_STACK null_write    P_((FILEPTR *f, const char *buf, long bytes));
  50. long    ARGS_ON_STACK null_read    P_((FILEPTR *f, char *buf, long bytes));
  51. long    ARGS_ON_STACK null_lseek    P_((FILEPTR *f, long where, int whence));
  52. long    ARGS_ON_STACK null_ioctl    P_((FILEPTR *f, int mode, void *buf));
  53. long    ARGS_ON_STACK null_datime    P_((FILEPTR *f, short *time, int rwflag));
  54. long    ARGS_ON_STACK null_close    P_((FILEPTR *f, int pid));
  55. long    ARGS_ON_STACK null_select    P_((FILEPTR *f, long p, int mode));
  56. void    ARGS_ON_STACK null_unselect    P_((FILEPTR *f, long p, int mode));
  57.  
  58. static long ARGS_ON_STACK mouse_open    P_((FILEPTR *f));
  59. static long ARGS_ON_STACK mouse_read    P_((FILEPTR *f, char *buf, long nbytes));
  60. static long ARGS_ON_STACK mouse_ioctl P_((FILEPTR *f, int mode, void *buf));
  61. static long ARGS_ON_STACK mouse_close P_((FILEPTR *f, int pid));
  62. static long ARGS_ON_STACK mouse_select P_((FILEPTR *f, long p, int mode));
  63. static void ARGS_ON_STACK mouse_unselect P_((FILEPTR *f, long p, int mode));
  64.  
  65. /* device driver for BIOS terminals */
  66.  
  67. DEVDRV bios_tdevice = {
  68.     bios_topen, bios_twrite, bios_tread, bios_tseek, bios_ioctl,
  69.     null_datime, bios_close, bios_select, bios_unselect,
  70.     bios_writeb, bios_readb
  71. };
  72.  
  73. /* device driver for BIOS devices that are not terminals */
  74.  
  75. DEVDRV bios_ndevice = {
  76.     null_open, bios_nwrite, bios_nread, null_lseek, bios_ioctl,
  77.     null_datime, bios_close, bios_select, bios_unselect
  78. };
  79.  
  80. DEVDRV null_device = {
  81.     null_open, null_write, null_read, null_lseek, null_ioctl,
  82.     null_datime, null_close, null_select, null_unselect
  83. };
  84.  
  85. DEVDRV mouse_device = {
  86.     mouse_open, null_write, mouse_read, null_lseek, mouse_ioctl,
  87.     null_datime, mouse_close, mouse_select, mouse_unselect
  88. };
  89.  
  90. /* this special driver is checked for in dosfile.c, and indicates that
  91.  * a dup operation is actually wanted rather than an open
  92.  */
  93. DEVDRV fakedev;
  94.  
  95. #ifdef FASTTEXT
  96. extern DEVDRV screen_device;    /* see fasttext.c */
  97. #endif
  98.  
  99. FILESYS bios_filesys = {
  100.     (FILESYS *)0,
  101.     FS_LONGPATH,
  102.     bios_root,
  103.     bios_lookup, nocreat, bios_getdev, bios_getxattr,
  104.     bios_chattr, bios_chown, bios_chmode,
  105.     nomkdir, bios_rmdir, bios_remove, bios_getname, bios_rename,
  106.     bios_opendir, bios_readdir, bios_rewinddir, bios_closedir,
  107.     bios_pathconf, bios_dfree, nowritelabel, noreadlabel,
  108.     bios_symlink, bios_readlink, nohardlink, bios_fscntl, nodskchng
  109. };
  110.  
  111.  
  112. struct tty con_tty, aux_tty, midi_tty;
  113. struct tty sccb_tty, scca_tty, ttmfp_tty;
  114.  
  115. struct bios_file BDEV[] = {
  116.  
  117. /* "real" bios devices present on all machines */
  118.     {"centr", &bios_ndevice, 0, 0, 0, 0},
  119.     {"console", &bios_tdevice, 2, O_TTY, &con_tty, 0},
  120.     {"midi", &bios_tdevice, 3, O_TTY, &midi_tty, 0},
  121.     {"kbd", &bios_ndevice, 4, 0, 0, 0},
  122. /* devices that duplicate handles */
  123.     {"prn", &fakedev, -3, 0, 0, 0}, /* handle -3 (printer) */
  124.     {"aux", &fakedev, -2, 0, 0, 0}, /* handle -2 (aux. terminal) */
  125.     {"con", &fakedev, -1, 0, 0, 0}, /* handle -1 (control terminal) */
  126.     {"tty", &fakedev, -1, 0, 0, 0}, /* the Unix name for it */
  127.     {"stdin", &fakedev, 0, 0, 0, 0},  /* handle 0 (stdin) */
  128.     {"stdout", &fakedev, 1, 0, 0, 0}, /* handle 1 (stdout) */
  129.     {"stderr", &fakedev, 2, 0, 0, 0}, /* handle 2 (stderr) */
  130.     {"fd", &fakedev, S_IFDIR, 0, 0, 0}, /* file descriptor directory */
  131.  
  132. /* other miscellaneous devices */
  133.     {"mouse", &mouse_device, 0, 0, 0, 0},
  134.     {"null", &null_device, 0, 0, 0, 0},
  135.  
  136. #ifdef FASTTEXT
  137. /* alternate console driver */
  138.     {"fasttext", &screen_device, 2, O_TTY, &con_tty, 0},
  139. #endif
  140.  
  141. /* serial port things *must* come last, because not all of these
  142.  * are present on all machines (except for modem1, which does however
  143.  * have a different device number on TTs and STs)
  144.  */
  145.     {"modem1", &bios_tdevice, 6, O_TTY, &aux_tty, 0},
  146.     {"modem2", &bios_tdevice, 7, O_TTY, &sccb_tty, 0},
  147.     {"serial1", &bios_tdevice, 8, O_TTY, &ttmfp_tty, 0},
  148.     {"serial2", &bios_tdevice, 9, O_TTY, &scca_tty, 0},
  149.     {"", 0, 0, 0, 0, 0}
  150. };
  151.  
  152. #define xconstat ((long *)0x51eL)
  153. #define xconin     ((long *)0x53eL)
  154. #define xcostat ((long *)0x55eL)
  155. #define xconout    ((long *)0x57eL)
  156.  
  157. extern BCONMAP2_T *bconmap2;        /* bconmap struct */
  158. #define MAPTAB (bconmap2->maptab)
  159.  
  160. #define MAXBAUD 16
  161.  
  162. /* keep these sorted in descending order */
  163. static long baudmap[MAXBAUD] = {
  164. 19200L, 9600L, 4800L, 3600L, 2400L, 2000L, 1800L, 1200L,
  165. 600L, 300L, 200L, 150L, 134L, 110L, 75L, 50L
  166. };
  167.  
  168. /* set/reset bits in SCC w5 */
  169. INLINE static void scc_set5 P_((volatile char *control, int setp,
  170.     unsigned bits, IOREC_T *iorec));
  171.  
  172. INLINE static void scc_set5 (control, setp, bits, iorec)
  173. volatile char *control;
  174. int setp;
  175. unsigned bits;
  176. IOREC_T *iorec;
  177. {
  178.     volatile char dummy;
  179.  
  180.     short sr = spl7();
  181.  
  182. #if 1
  183. /* sanity check: if the w5 copy at offset 1d has bit 3 off something is wrong */
  184.     if (!(((char *) iorec)[0x1d] & 8)) {
  185.         spl(sr);
  186.         ALERT ("scc_set5: iorec %lx w5 copy has sender enable bit off, w5 not changed", iorec);
  187.         return;
  188.     }
  189. #endif
  190.     dummy = *((volatile char *) 0xfffffa01L);
  191.     *control = 5;
  192.     dummy = *((volatile char *) 0xfffffa01L);
  193.     if (setp)
  194.         *control = (((char *) iorec)[0x1d] |= bits);
  195.     else
  196.         *control = (((char *) iorec)[0x1d] &= ~bits);
  197.     spl(sr);
  198. #ifdef __TURBOC__
  199.     setp = dummy; /* jr: get rid of warning regarding dummy */
  200. #endif
  201. }
  202.  
  203. #define    MAX_BTTY    4    /* 4 bios_tty structs */
  204.  
  205. /* find bios_tty struct for a FILEPTR
  206.  */
  207. #define BTTY(f) ((((struct tty *)(f)->devinfo) == &aux_tty) ? bttys : \
  208.          ((has_bconmap && (unsigned)(f)->fc.aux-6 < btty_max) ? \
  209.             bttys+(f)->fc.aux-6 : 0))
  210.  
  211. struct bios_tty bttys[MAX_BTTY], midi_btty;
  212. short    btty_max;
  213.  
  214. /* RSVF cookie value (read in main.c) */
  215. long rsvf;
  216.  
  217. /* try to get a fd for a BIOS tty to pass some ioctls to... */
  218.  
  219. INLINE static short
  220. rsvf_open(bdev)
  221.     int bdev;
  222. {
  223.     long ret = EUNDEV;
  224.     struct rsvfdev {
  225.         union {
  226.             char *name;
  227.             struct rsvfdev *next;
  228.         } f;
  229.         char flags, unused1, bdev, unused2;
  230.     } *r = (struct rsvfdev *)rsvf;
  231.  
  232.     while (r) {
  233.         if (r->flags >= 0) {
  234.             r = r->f.next;
  235.             continue;
  236.         }
  237.         if ((r->flags & 0xe0) == 0xe0 && r->bdev == bdev) {
  238.             char rname[0x80] = "u:\\dev\\";
  239.  
  240.             strncpy (rname + sizeof "u:\\dev\\" - 1, r->f.name,
  241.                 sizeof rname - sizeof "u:\\dev\\");
  242.             ret = Fopen (rname, O_RDWR);
  243.             if (ret < MIN_HANDLE || ret > 0x8000) {
  244.                 ALERT ("rsvf_open(%d): Fopen %s returned %lx",
  245.                     bdev, rname, ret);
  246.                 return EUNDEV;
  247.             }
  248.             break;
  249.         }
  250.         ++r;
  251.     }
  252.     return ret;
  253. }
  254.  
  255. INLINE static long
  256. rsvf_close(f)
  257.     int f;
  258. {
  259.     long ret = EIHNDL;
  260.     if (f != EUNDEV) {
  261.         ret = Fclose (f);
  262.         if (ret)
  263.             ALERT ("rsvf_close(%d): Fclose %x returned %lx", f, ret);
  264.     }
  265.     return ret;
  266. }
  267.  
  268. INLINE long
  269. rsvf_ioctl(f, arg, mode)
  270.     int f;
  271.     void *arg;
  272.     int mode;
  273. {
  274.     if (f == EUNDEV)
  275.         return EINVFN;
  276.     TRACE(("rsvf_ioctl: passing ioctl %x (tosfd=0x%x)", mode, f));
  277.     /* is there a more direct way than this? */
  278.     return Fcntl (f, (long)arg, mode);
  279. }
  280.  
  281. extern int tosvers;    /* from main.c */
  282.  
  283. /* Does the fcookie fc refer to the \dev\fd directory? */
  284. #define IS_FD_DIR(fc) ((fc)->aux == S_IFDIR)
  285. /* Does the fcookie fc refer to a file in the \dev\fd directory? */
  286. #define IS_FD_ENTRY(fc) ((fc)->index > 0 && (fc)->index <= MAX_OPEN-MIN_HANDLE)
  287.  
  288. struct bios_file *broot, *bdevlast;
  289.  
  290. /* a file pointer for BIOS device 1, provided only for insurance
  291.  * in case a Bconmap happens and we can't allocate a new FILEPTR;
  292.  * in most cases, we'll want to build a FILEPTR in the usual
  293.  * way.
  294.  */
  295.  
  296. FILEPTR *defaultaux;
  297.  
  298. /* ts: a xattr field used for the root directory, 'cause there's no
  299.  * bios_file structure for it.
  300.  */
  301. XATTR rxattr;
  302. XATTR fdxattr;
  303.  
  304. /* ts: a small utility function to set up a xattr structure
  305.  */
  306.  
  307. static void set_xattr P_((XATTR *xp, ushort mode, int rdev));
  308.  
  309. void set_xattr(xp, mode, rdev)
  310.     XATTR *xp;
  311.     ushort mode;
  312.     int rdev;
  313. {
  314.     xp->mode = mode;
  315.     xp->index = 0L;
  316.     xp->dev = BIOSDRV;
  317.     xp->rdev = rdev;
  318.     xp->nlink = 1;
  319.     xp->uid = curproc->euid;
  320.     xp->gid = curproc->egid;
  321.     xp->size = 0L;
  322.     xp->blksize = 1024L;
  323.     xp->nblocks = 0L;
  324.  
  325.     xp->mtime = xp->atime = xp->ctime = timestamp;
  326.     xp->mdate = xp->adate = xp->cdate = datestamp;
  327.  
  328. /* root directory only */
  329.     if ((mode & S_IFMT) == S_IFDIR)
  330.         xp->attr = FA_DIR;
  331.     else
  332.         xp->attr = 0;
  333.     xp->reserved2 = 0;
  334.     xp->reserved3[0] = 0L;
  335.     xp->reserved3[1] = 0L;
  336. }
  337.  
  338. void
  339. biosfs_init()
  340. {
  341.     struct bios_file *b, *c;
  342.     int majdev, mindev;
  343.     int i;
  344.  
  345.     broot = BDEV;
  346.  
  347.     c = (struct bios_file *)0;
  348.     for (b = broot; b->name[0]; b++) {
  349.         b->next = b+1;
  350.  
  351.     /* Save a pointer to the first serial port */
  352.         if (b->private == 6)
  353.             c = b;
  354.         if (b->device->readb && b->tty != &con_tty)
  355.     /* device has DEVDRV calls beyond unselect */
  356.             b->drvsize = offsetof (DEVDRV, readb) + sizeof (long);
  357.  
  358.     /* if not a TT or Mega STE, adjust the MODEM1 device to be BIOS
  359.      * device 1
  360.      * and ignore the remaining devices, since they're not present
  361.      */
  362.         if (b->private == 6 &&
  363.             (!has_bconmap || bconmap2->maptabsize == 1)) {
  364.             if (!has_bconmap)
  365.                 b->private = 1;
  366.             b->next = 0;
  367.             break;
  368.         }
  369.     /* SERIAL1(!) is not present on the Mega STe or Falcon,
  370.      * device 8 is SCC channel A
  371.      */
  372.         if (mch != TT && b->private == 8) {
  373.             b->name[6] = '2';    /* "serial2" */
  374.             b->tty = &scca_tty;
  375.             b->next = 0;
  376.             break;
  377.         }
  378.     }
  379.     bdevlast = b;
  380.     if (b->name[0] == 0) {
  381.         --b;
  382.         b->next = 0;
  383.     }
  384.     /* Initialize bios_tty structures */
  385.     for (i=0;c && i<MAX_BTTY;c=c->next, i++) {
  386.         if (has_bconmap)
  387.             bttys[i].irec = MAPTAB[c->private-6].iorec;
  388.         else
  389.             bttys[i].irec = Iorec(0);
  390.         bttys[i].orec = bttys[i].irec+1;
  391.         bttys[i].rsel = &(c->tty->rsel);
  392.         bttys[i].wsel = &(c->tty->wsel);
  393.         bttys[i].baudmap = baudmap;
  394.         bttys[i].maxbaud = MAXBAUD;
  395.         bttys[i].baudx = NULL;
  396.         *c->tty = default_tty;
  397.         bttys[i].tty = c->tty;
  398.         bttys[i].clocal = 1;    /* default off would be better but
  399.                        likely confuses old programs... :/ */
  400.         bttys[i].brkint = 1;
  401.         bttys[i].tosfd = EUNDEV;
  402.         bttys[i].bdev = c->private;
  403.     }
  404.     btty_max = i;
  405.  
  406.     midi_btty.irec = Iorec(2);
  407.     midi_btty.rsel = &midi_tty.rsel;
  408.     midi_btty.wsel = &midi_tty.wsel;
  409.     midi_btty.tty = &midi_tty;
  410.     midi_tty = default_tty;
  411.     midi_btty.clocal = 1;
  412.     midi_btty.tosfd = EUNDEV;
  413.     midi_btty.bdev = 3;
  414.  
  415.     defaultaux = new_fileptr();
  416.     defaultaux->links = 1;        /* so it never gets freed */
  417.     defaultaux->flags = O_RDWR;
  418.     defaultaux->pos = 0;
  419.     defaultaux->devinfo = 0;
  420.     defaultaux->fc.fs = &bios_filesys;
  421.     defaultaux->fc.index = 0;
  422.     defaultaux->fc.aux = 1;
  423.     defaultaux->fc.dev = BIOSDRV;
  424.     defaultaux->dev = &bios_ndevice;
  425.  
  426. /* set up XATTR fields */
  427.     set_xattr(&rxattr, S_IFDIR|DEFAULT_DIRMODE, BIOSDRV);
  428.     set_xattr(&fdxattr, S_IFDIR|DEFAULT_DIRMODE, BIOSDRV);
  429.  
  430.     for (b = BDEV; b; b = b->next) {
  431.         if (b->device == &bios_ndevice || b->device == &bios_tdevice) {
  432.             majdev = BIOS_RDEV;
  433.             mindev = b->private;
  434.         } else if (b->device == &fakedev) {
  435.             majdev = FAKE_RDEV;
  436.             mindev = b->private;
  437.         } else {
  438.             majdev = UNK_RDEV;
  439.             mindev = b->private;
  440.         }
  441.         set_xattr(&b->xattr, S_IFCHR|DEFAULT_MODE,
  442.               majdev | (mindev & 0x00ff) );
  443.     }
  444. }
  445.  
  446. static long ARGS_ON_STACK 
  447. bios_root(drv, fc)
  448.     int drv;
  449.     fcookie *fc;
  450. {
  451.     if (drv == BIOSDRV) {
  452.         fc->fs = &bios_filesys;
  453.         fc->dev = drv;
  454.         fc->index = 0L;
  455.         return 0;
  456.     }
  457.     fc->fs = 0;
  458.     return EINTRN;
  459. }
  460.  
  461. static long ARGS_ON_STACK 
  462. bios_lookup(dir, name, fc)
  463.     fcookie *dir;
  464.     const char *name;
  465.     fcookie *fc;
  466. {
  467.     struct bios_file *b;
  468.  
  469.     if (dir->index != 0) {
  470.     /* check for \dev\fd directory */
  471.         if (!IS_FD_DIR(dir)) {
  472.             DEBUG(("bios_lookup: bad directory"));
  473.             return EPTHNF;
  474.         }
  475.         if (!*name || (name[0] == '.' && name[1] == 0)) {
  476.             *fc = *dir;
  477.             return 0;
  478.         }
  479.         if (!strcmp(name, "..")) {
  480.         /* root directory */
  481.             fc->fs = &bios_filesys;
  482.             fc->dev = dir->dev;
  483.             fc->index = 0L;
  484.             return 0;
  485.         }
  486.         if (isdigit(*name) || *name == '-') {
  487.             int fd = (int) atol(name);
  488.             if (fd >= MIN_HANDLE && fd < MAX_OPEN) {
  489.                 fc->fs = &bios_filesys;
  490.                 fc->dev = dir->dev;
  491.                 fc->aux = fd;
  492.                 fc->index = fd - MIN_HANDLE + 1;
  493.                 return 0;
  494.             }
  495.         }
  496.         DEBUG(("bios_lookup: name (%s) not found", name));
  497.         return EFILNF;
  498.     }
  499.  
  500. /* special case: an empty name in a directory means that directory */
  501. /* so does "." */
  502.     if (!*name || (name[0] == '.' && name[1] == 0)) {
  503.         *fc = *dir;
  504.         return 0;
  505.     }
  506.  
  507. /* another special case: ".." could be a mount point */
  508.     if (!strcmp(name, "..")) {
  509.         *fc = *dir;
  510.         return EMOUNT;
  511.     }
  512.  
  513.     for (b = broot; b; b = b->next) {
  514.         if (!stricmp(b->name, name)) {
  515.             fc->fs = &bios_filesys;
  516.             fc->index = (long)b;
  517.             fc->aux = b->private;
  518.             fc->dev = dir->dev;
  519.             return 0;
  520.         }
  521.     }
  522.     DEBUG(("bios_lookup: name(%s) not found", name));
  523.     return EFILNF;
  524. }
  525.  
  526. static long ARGS_ON_STACK 
  527. bios_getxattr(fc, xattr)
  528.     fcookie *fc;
  529.     XATTR *xattr;
  530. {
  531. #ifdef FOLLOW_XATTR_CHAIN
  532.     FILEPTR *f;
  533.     long r;
  534. #endif
  535.     struct bios_file *b = (struct bios_file *)fc->index;
  536.     int majdev, mindev;
  537.  
  538.     majdev = UNK_RDEV;
  539.     mindev = 0;
  540.  
  541.     if (fc->index == 0) {            /* root directory? */
  542.         *xattr = rxattr;
  543.         xattr->index = fc->index;
  544.         xattr->dev = fc->dev;
  545.     } else if (IS_FD_DIR(fc)) {        /* fd directory? */
  546.         *xattr = fdxattr;
  547.         xattr->index = fc->index;
  548.         xattr->dev = fc->dev;
  549.     } else if (IS_FD_ENTRY(fc)) {
  550.         /* u:\dev\fd\n */
  551. #ifdef FOLLOW_XATTR_CHAIN
  552.         f = curproc->handle[(int)fc->aux];
  553.         if (f) {
  554.             r = (*f->fc.fs->getxattr)(&f->fc, xattr);
  555.             if (r < 0)
  556.                 return r;
  557.         } else {
  558. #endif
  559.             majdev = FAKE_RDEV;
  560.             mindev = ((int)fc->aux) & 0x00ff;
  561.             set_xattr(xattr, S_IFCHR | DEFAULT_MODE, majdev|mindev);
  562. #ifndef FOLLOW_XATTR_CHAIN
  563.             xattr->index = fc->index;
  564. #else
  565.         }
  566. #endif
  567.     } else if (b->device == &fakedev) {
  568. #ifdef FOLLOW_XATTR_CHAIN
  569.         if ((f = curproc->handle[b->private]) != 0) {
  570.             /* u:\dev\stdin, u:\dev\stdout, etc. */
  571.             r = (*f->fc.fs->getxattr) (&f->fc, xattr);
  572.             if (r < 0) return r;
  573.         } else {
  574. #endif
  575.             majdev = FAKE_RDEV;
  576.             mindev = ((int)b->private) & 0x00ff;
  577.             set_xattr(xattr, S_IFCHR|DEFAULT_MODE, majdev|mindev);
  578. #ifndef FOLLOW_XATTR_CHAIN
  579.             xattr->index = fc->index;
  580. #else
  581.         }
  582. #endif
  583.     } else {
  584.         *xattr = b->xattr;
  585.         xattr->index = fc->index;
  586.         xattr->dev = fc->dev;
  587.     }
  588.     return 0;
  589. }
  590.  
  591. static long ARGS_ON_STACK 
  592. bios_chattr(fc, attrib)
  593.     fcookie *fc;
  594.     int attrib;
  595. {
  596.     UNUSED(fc); UNUSED(attrib);
  597.     return EACCDN;
  598. }
  599.  
  600. static long ARGS_ON_STACK 
  601. bios_chown(fc, uid, gid)
  602.     fcookie *fc;
  603.     int uid, gid;
  604. {
  605.     struct bios_file *b = (struct bios_file *)fc->index;
  606.  
  607.     if (!(curproc->euid)) {
  608.         if (!b) {
  609.             /* a directory */
  610.             rxattr.uid = uid;
  611.             rxattr.gid = gid;
  612.         } else if (IS_FD_DIR(fc)) {
  613.             fdxattr.uid = uid;
  614.             fdxattr.gid = gid;
  615.         } else if (!IS_FD_ENTRY(fc)) {
  616.             /* any other entry */
  617.             b->xattr.uid = uid;
  618.             b->xattr.gid = gid;
  619.         }
  620.         return 0;
  621.     }
  622.  
  623.     return EACCDN;
  624. }
  625.  
  626. static long ARGS_ON_STACK 
  627. bios_chmode(fc, mode)
  628.     fcookie *fc;
  629.     unsigned mode;
  630. {
  631.     struct bios_file *b = (struct bios_file *)fc->index;
  632.  
  633.     if (!b) {
  634.         /* root directory */
  635.         if (!curproc->euid || (curproc->euid == rxattr.uid)) {
  636.             rxattr.mode = (rxattr.mode & S_IFMT) | mode;
  637.             return 0;
  638.         }
  639.     } else if (IS_FD_DIR(fc)) {
  640.         if (!curproc->euid || (curproc->euid == fdxattr.uid)) {
  641.             fdxattr.mode = (fdxattr.mode & S_IFMT) | mode;
  642.             return 0;
  643.         }
  644.     } else if (!IS_FD_ENTRY(fc)) {
  645.         if (!curproc->euid && (curproc->euid == b->xattr.uid)) {
  646.             b->xattr.mode = (b->xattr.mode & S_IFMT) | mode;
  647.             return 0;
  648.         }
  649.     }
  650.  
  651.     return EACCDN;
  652. }
  653.  
  654. long ARGS_ON_STACK 
  655. nomkdir(dir, name, mode)
  656.     fcookie *dir;
  657.     const char *name;
  658.     unsigned mode;
  659. {
  660.     UNUSED(dir); UNUSED(name);
  661.     UNUSED(mode);
  662.     return EACCDN;
  663. }
  664.  
  665. static long ARGS_ON_STACK 
  666. bios_rmdir(dir, name)
  667.     fcookie *dir;
  668.     const char *name;
  669. {
  670.     return bios_remove(dir, name);
  671. }
  672.  
  673. /*
  674.  * MAJOR BUG: we don't check here for removal of devices for which there
  675.  * are still open files
  676.  */
  677.  
  678. static long ARGS_ON_STACK 
  679. bios_remove(dir, name)
  680.     fcookie *dir;
  681.     const char *name;
  682. {
  683.     struct bios_file *b, **lastb;
  684.  
  685.     if (curproc->euid)
  686.         return EACCDN;
  687.  
  688. /* don't allow removal in the fd directory */
  689.     if (IS_FD_DIR(dir))
  690.         return EACCDN;
  691.  
  692.     lastb = &broot;
  693.     for (b = broot; b; b = *(lastb = &b->next)) {
  694.         if (!stricmp(b->name, name)) break;
  695.     }
  696.     if (!b) return EFILNF;
  697.  
  698. /* don't allow removal of the device if we don't own it */
  699.     if (curproc->euid && (curproc->euid != b->xattr.uid)) {
  700.         return EACCDN;
  701.     }
  702.  
  703. /* don't allow removal of the basic system devices */
  704.     if (b >= BDEV && b <= bdevlast) {
  705.         return EACCDN;
  706.     }
  707.     *lastb = b->next;
  708.  
  709.     if (b->device == 0 || b->device == &bios_tdevice)
  710.         kfree(b->tty);
  711.  
  712.     kfree(b);
  713.     return 0;
  714. }
  715.  
  716. static long ARGS_ON_STACK 
  717. bios_getname(root, dir, pathname, size)
  718.     fcookie *root, *dir; char *pathname;
  719.     int size;
  720. {
  721.     char *foo;
  722.  
  723.     if (size == 0)
  724.       return ERANGE;
  725.     if (root->index == dir->index) {
  726.         *pathname = 0;
  727.         return 0;
  728.     }
  729.     /* DIR must point to the fd directory */
  730.     if (!IS_FD_DIR (dir))
  731.         return EINTRN;
  732.     *pathname++ = '\\';
  733.     size--;
  734.     foo = ((struct bios_file *)dir->index)->name;
  735.     if (strlen(foo) < size)
  736.         strcpy(pathname, foo);
  737.     else
  738.         return ERANGE;
  739.     return 0;
  740. }
  741.  
  742. static long ARGS_ON_STACK 
  743. bios_rename(olddir, oldname, newdir, newname)
  744.     fcookie *olddir;
  745.     char *oldname;
  746.     fcookie *newdir;
  747.     const char *newname;
  748. {
  749.     struct bios_file *b, *be = 0;
  750.  
  751.     UNUSED(olddir); UNUSED(newdir);
  752.  
  753.     if (curproc->euid)
  754.         return EACCDN;
  755.  
  756.     for (b = broot; b; b = b->next) {
  757.         if (!stricmp(b->name, newname)) {
  758.             return EACCDN;
  759.         }
  760.         if (!stricmp(b->name, oldname)) {
  761.             be = b;
  762.         }
  763.     }
  764.     if (be) {
  765.         strncpy(be->name, newname, BNAME_MAX);
  766.         return 0;
  767.     }
  768.     return EFILNF;
  769. }
  770.  
  771. static long ARGS_ON_STACK 
  772. bios_opendir(dirh, flags)
  773.     DIR *dirh;
  774.     int flags;
  775. {
  776.     UNUSED(flags);
  777.  
  778.     if (dirh->fc.index != 0 && !IS_FD_DIR(&dirh->fc)) {
  779.         DEBUG(("bios_opendir: bad directory"));
  780.         return EPTHNF;
  781.     }
  782.     return 0;
  783. }
  784.  
  785. static long ARGS_ON_STACK 
  786. bios_readdir(dirh, name, namelen, fc)
  787.     DIR *dirh;
  788.     char *name;
  789.     int namelen;
  790.     fcookie *fc;
  791. {
  792.     struct bios_file *b;
  793.     int giveindex = dirh->flags == 0;
  794.     int i;
  795.     char buf[5];
  796.  
  797.     if (IS_FD_DIR(&dirh->fc)) {
  798.         i = dirh->index++;
  799.         if (i+MIN_HANDLE >= MAX_OPEN)
  800.             return ENMFIL;
  801.         fc->fs = &bios_filesys;
  802.         fc->index = i+1;
  803.         fc->aux = i+MIN_HANDLE;
  804.         fc->dev = dirh->fc.dev;
  805.         if (giveindex) {
  806.             namelen -= (int)sizeof(long);
  807.             if (namelen <= 0)
  808.                 return ERANGE;
  809.             *(long *)name = (long)i + 1;
  810.             name += sizeof(long);
  811.         }
  812.         ksprintf(buf, "%d", i+MIN_HANDLE);
  813.         strncpy(name, buf, namelen - 1);
  814.         if (strlen(buf) >= namelen)
  815.             return ENAMETOOLONG;
  816.         return 0;
  817.     }
  818.  
  819.     b = broot;
  820.     i = dirh->index++;
  821.     while(i-- > 0) {
  822.         if (!b) break;
  823.         b = b->next;
  824.     }
  825.     if (!b) {
  826.         return ENMFIL;
  827.     }
  828.     fc->fs = &bios_filesys;
  829.     fc->index = (long)b;
  830.     fc->aux = b->private;
  831.     fc->dev = dirh->fc.dev;
  832.     if (giveindex) {
  833.         namelen -= (int)sizeof(long);
  834.         if (namelen <= 0)
  835.             return ERANGE;
  836.         *((long *)name) = (long) b;
  837.         name += sizeof(long);
  838.     }
  839.     strncpy(name, b->name, namelen-1);
  840.     if (strlen(b->name) >= namelen)
  841.         return ENAMETOOLONG;
  842.     return 0;
  843. }
  844.  
  845. static long ARGS_ON_STACK 
  846. bios_rewinddir(dirh)
  847.     DIR *dirh;
  848. {
  849.     dirh->index = 0;
  850.     return 0;
  851. }
  852.  
  853. static long ARGS_ON_STACK 
  854. bios_closedir(dirh)
  855.     DIR *dirh;
  856. {
  857.     UNUSED(dirh);
  858.     return 0;
  859. }
  860.  
  861. static long ARGS_ON_STACK 
  862. bios_pathconf(dir, which)
  863.     fcookie *dir;
  864.     int which;
  865. {
  866.     UNUSED(dir);
  867.  
  868.     switch(which) {
  869.     case -1:
  870.         return DP_MAXREQ;
  871.     case DP_IOPEN:
  872.         return UNLIMITED;    /* no limit on BIOS file descriptors */
  873.     case DP_MAXLINKS:
  874.         return 1;        /* no hard links available */
  875.     case DP_PATHMAX:
  876.         return PATH_MAX;
  877.     case DP_NAMEMAX:
  878.         return BNAME_MAX;
  879.     case DP_ATOMIC:
  880.         return 1;        /* no atomic writes */
  881.     case DP_TRUNC:
  882.         return DP_AUTOTRUNC;    /* names are truncated */
  883.     case DP_CASE:
  884.         return DP_CASEINSENS;    /* not case sensitive */
  885.     case DP_MODEATTR:
  886.         return (0777L << 8)|
  887.                 DP_FT_DIR|DP_FT_CHR;
  888.     case DP_XATTRFIELDS:
  889.         return DP_INDEX|DP_DEV|DP_RDEV|DP_NLINK|DP_UID|DP_GID;
  890.     default:
  891.         return EINVFN;
  892.     }
  893. }
  894.  
  895. static long ARGS_ON_STACK 
  896. bios_dfree(dir, buf)
  897.     fcookie *dir;
  898.     long *buf;
  899. {
  900.     UNUSED(dir);
  901.  
  902.     buf[0] = 0;    /* number of free clusters */
  903.     buf[1] = 0;    /* total number of clusters */
  904.     buf[2] = 1;    /* sector size (bytes) */
  905.     buf[3] = 1;    /* cluster size (sectors) */
  906.     return 0;
  907. }
  908.  
  909. /*
  910.  * BIOS Dcntl() calls:
  911.  * Dcntl(0xde02, "U:\DEV\FOO", &foo_descr): install a new device called
  912.  *     "FOO", which is described by the dev_descr structure "foo_descr".
  913.  *     this structure has the following fields:
  914.  *         DEVDRV *driver        the device driver itself
  915.  *       short  dinfo            info for the device driver
  916.  *       short  flags            flags for the file (e.g. O_TTY)
  917.  *       struct tty *tty        tty structure, if appropriate
  918.  *       long   drvsize;        size of driver struct
  919.  *
  920.  * Dcntl(0xde00, "U:\DEV\BAR", n): install a new BIOS terminal device, with
  921.  *     BIOS device number "n".
  922.  * Dcntl(0xde01, "U:\DEV\BAR", n): install a new non-tty BIOS device, with
  923.  *     BIOS device number "n".
  924.  */
  925.  
  926. static long ARGS_ON_STACK
  927. bios_fscntl(dir, name, cmd, arg)
  928.     fcookie *dir;
  929.     const char *name;
  930.     int cmd;
  931.     long arg;
  932. {
  933.     struct bios_file *b;
  934.     static int devindex = 0;
  935.  
  936.     if (curproc->euid) {
  937.         DEBUG(("biosfs: Dcntl() by non-privileged process"));
  938.         return ((unsigned)cmd == DEV_INSTALL) ? 0 : EACCDN;
  939.     }
  940.  
  941.     if (IS_FD_DIR(dir))
  942.         return EACCDN;
  943.  
  944.     /* ts: let's see if such an entry already exists */
  945.     for (b=broot; b; b=b->next)
  946.         if (!strcmp(b->name, name))
  947.             break;
  948.  
  949.     switch((unsigned)cmd) {
  950.     case DEV_INSTALL:
  951.         {
  952.         struct dev_descr *d = (struct dev_descr *)arg;
  953.  
  954.         if (!b) {
  955.             b = kmalloc(SIZEOF(struct bios_file));
  956.             if (!b) return 0;
  957.             b->next = broot;
  958.             broot = b;
  959.             strncpy(b->name, name, BNAME_MAX);
  960.             b->name[BNAME_MAX] = 0;
  961.         }
  962.         b->device = d->driver;
  963.         b->private = d->dinfo;
  964.         b->flags = d->flags;
  965.         b->tty = d->tty;
  966.         b->drvsize = d->drvsize;
  967.         set_xattr(&(b->xattr), S_IFCHR|DEFAULT_MODE, UNK_RDEV|devindex);
  968.         devindex = (devindex+1) & 0x00ff;
  969.         return (long)&kernelinfo;
  970.         }
  971.     case DEV_NEWTTY:
  972.         if (!b) {
  973.             b = kmalloc(SIZEOF(struct bios_file));
  974.             if (!b)
  975.                 return ENSMEM;
  976.             strncpy(b->name, name, BNAME_MAX);
  977.             b->name[BNAME_MAX] = 0;
  978.             b->tty = kmalloc(SIZEOF(struct tty));
  979.             if (!b->tty) {
  980.                 kfree(b);
  981.                 return ENSMEM;
  982.             }
  983.             b->next = broot;
  984.             broot = b;
  985.         } else {
  986.             /*  ts: it's probably better to use a new tty
  987.              * structure here, but don't touch the old
  988.              * pointers until we know we've got enough
  989.              * memory to do it!
  990.              */
  991.             struct tty *ttyptr;
  992.  
  993.             if ((ttyptr = kmalloc(SIZEOF(struct tty))) == 0)
  994.                 return ENSMEM;
  995.             b->tty = ttyptr;
  996.         }
  997.         b->drvsize = 0;
  998.         b->device = &bios_tdevice;
  999.         b->private = arg;
  1000.         b->flags = O_TTY;
  1001.         *b->tty = default_tty;
  1002.         set_xattr(&(b->xattr), S_IFCHR|DEFAULT_MODE, BIOS_RDEV|(b->private&0x00ff));
  1003.         return 0;
  1004.  
  1005.     case DEV_NEWBIOS:
  1006.         if (!b) {
  1007.             b = kmalloc(SIZEOF(struct bios_file));
  1008.             if (!b) return ENSMEM;
  1009.             b->next = broot;
  1010.             broot = b;
  1011.             strncpy(b->name, name, BNAME_MAX);
  1012.             b->name[BNAME_MAX] = 0;
  1013.         }
  1014.         b->drvsize = 0;
  1015.         /*  ts: it's probably better not to free an old tty
  1016.          * structure here, cause we don't know if any process
  1017.          * who didn't recognize this change is still using it.
  1018.          */
  1019.         b->tty = 0;
  1020.         b->device = &bios_ndevice;
  1021.         b->private = arg;
  1022.         b->flags = 0;
  1023.         set_xattr(&(b->xattr), S_IFCHR|DEFAULT_MODE, BIOS_RDEV|(b->private&0x00ff));
  1024.         return 0;
  1025.     default:
  1026.         return EINVFN;
  1027.     }
  1028. }
  1029.  
  1030. static long ARGS_ON_STACK 
  1031. bios_symlink(dir, name, to)
  1032.     fcookie *dir;
  1033.     const char *name, *to;
  1034. {
  1035.     struct bios_file *b;
  1036.     long r;
  1037.     fcookie fc;
  1038.  
  1039.     if (curproc->euid)
  1040.         return EACCDN;
  1041.  
  1042.     if (IS_FD_DIR(dir))
  1043.         return EACCDN;
  1044.  
  1045.     r = bios_lookup(dir, name, &fc);
  1046.     if (r == 0) return EACCDN;    /* file already exists */
  1047.     if (r != EFILNF) return r;    /* some other error */
  1048.  
  1049.     b = kmalloc(SIZEOF(struct bios_file));
  1050.     if (!b) return EACCDN;
  1051.  
  1052.     strncpy(b->name, name, BNAME_MAX);
  1053.     b->name[BNAME_MAX] = 0;
  1054.     b->device = 0;
  1055.     b->private = EINVFN;
  1056.     b->flags = 0;
  1057.     b->tty = kmalloc((long)strlen(to)+1);
  1058.     if (!b->tty) {
  1059.         kfree(b);
  1060.         return EACCDN;
  1061.     }
  1062.     strcpy((char *)b->tty, to);
  1063.  
  1064.     set_xattr(&b->xattr, S_IFLNK|DEFAULT_DIRMODE, BIOSDRV);
  1065.     b->xattr.size = strlen(to)+1;
  1066.  
  1067.     b->next = broot;
  1068.     broot = b;
  1069.     return 0;
  1070. }
  1071.  
  1072. static long ARGS_ON_STACK 
  1073. bios_readlink(fc, buf, buflen)
  1074.     fcookie *fc;
  1075.     char *buf;
  1076.     int buflen;
  1077. {
  1078.     struct bios_file *b = (struct bios_file *)fc->index;
  1079.  
  1080.     if (IS_FD_DIR(fc) || IS_FD_ENTRY(fc))
  1081.         return EINVFN;
  1082.     if (!b) return EINVFN;
  1083.     if (b->device) return EINVFN;
  1084.  
  1085.     strncpy(buf, (char *)b->tty, buflen);
  1086.     if (strlen((char *)b->tty) >= buflen)
  1087.         return ENAMETOOLONG;
  1088.     return 0;
  1089. }
  1090.  
  1091.  
  1092. /*
  1093.  * routines for file systems that don't support volume labels
  1094.  */
  1095.  
  1096. long ARGS_ON_STACK 
  1097. nowritelabel(dir, name)
  1098.     fcookie *dir;
  1099.     const char *name;
  1100. {
  1101.     UNUSED(dir);
  1102.     UNUSED(name);
  1103.     return EACCDN;
  1104. }
  1105.  
  1106. long ARGS_ON_STACK 
  1107. noreadlabel(dir, name, namelen)
  1108.     fcookie *dir;
  1109.     char *name;
  1110.     int namelen;
  1111. {
  1112.     UNUSED(dir);
  1113.     UNUSED(name);
  1114.     UNUSED(namelen);
  1115.     return EFILNF;
  1116. }
  1117.  
  1118. /*
  1119.  * routines for file systems that don't support links
  1120.  */
  1121.  
  1122. long ARGS_ON_STACK 
  1123. nosymlink(dir, name, to)
  1124.     fcookie *dir;
  1125.     const char *name, *to;
  1126. {
  1127.     UNUSED(dir); UNUSED(name);
  1128.     UNUSED(to);
  1129.     return EINVFN;
  1130. }
  1131.  
  1132. long ARGS_ON_STACK 
  1133. noreadlink(dir, buf, buflen)
  1134.     fcookie *dir;
  1135.     char *buf;
  1136.     int buflen;
  1137. {
  1138.     UNUSED(dir); UNUSED(buf);
  1139.     UNUSED(buflen);
  1140.     return EINVFN;
  1141. }
  1142.  
  1143. long ARGS_ON_STACK 
  1144. nohardlink(fromdir, fromname, todir, toname)
  1145.     fcookie *fromdir, *todir;
  1146.     const char *fromname, *toname;
  1147. {
  1148.     UNUSED(fromdir); UNUSED(todir);
  1149.     UNUSED(fromname); UNUSED(toname);
  1150.     return EINVFN;
  1151. }
  1152.  
  1153. /* dummy routine for file systems with no Fscntl commands */
  1154.  
  1155. long ARGS_ON_STACK 
  1156. nofscntl(dir, name, cmd, arg)
  1157.     fcookie *dir;
  1158.     const char *name;
  1159.     int cmd;
  1160.     long arg;
  1161. {
  1162.     UNUSED(dir); UNUSED(name);
  1163.     UNUSED(cmd); UNUSED(arg);
  1164.     return EINVFN;
  1165. }
  1166.  
  1167. /*
  1168.  * Did the disk change? Not on this drive!
  1169.  * However, we have to do Getbpb anyways, because someone has decided
  1170.  * to force a media change on our (non-existent) drive.
  1171.  */
  1172. long ARGS_ON_STACK 
  1173. nodskchng(drv)
  1174.     int drv;
  1175. {
  1176.     (void)getbpb(drv);
  1177.     return 0;
  1178. }
  1179.  
  1180. long ARGS_ON_STACK 
  1181. nocreat(dir, name, mode, attrib, fc)
  1182.     fcookie *dir, *fc;
  1183.     const char *name;
  1184.     unsigned mode;
  1185.     int attrib;
  1186. {
  1187.     UNUSED(dir); UNUSED(fc);
  1188.     UNUSED(name); UNUSED(mode);
  1189.     UNUSED(attrib);
  1190.     return EACCDN;
  1191. }
  1192.  
  1193. static DEVDRV * ARGS_ON_STACK 
  1194. bios_getdev(fc, devsp)
  1195.     fcookie *fc;
  1196.     long *devsp;
  1197. {
  1198.     struct bios_file *b;
  1199.  
  1200.     /* Check for \dev\fd\... */
  1201.     if (IS_FD_ENTRY(fc)) {
  1202.         *devsp = (int) fc->aux;
  1203.         return &fakedev;
  1204.     }
  1205.  
  1206.     b = (struct bios_file *)fc->index;
  1207.  
  1208.     if (b->device && b->device != &fakedev)
  1209.         *devsp = (long)b->tty;
  1210.     else
  1211.         *devsp = b->private;
  1212.  
  1213.     return b->device;    /* return the device driver */
  1214. }
  1215.  
  1216. /*
  1217.  * NULL device driver
  1218.  */
  1219.  
  1220. long ARGS_ON_STACK 
  1221. null_open(f)
  1222.     FILEPTR *f;
  1223. {
  1224.     UNUSED(f);
  1225.     return 0;
  1226. }
  1227.  
  1228. long ARGS_ON_STACK 
  1229. null_write(f, buf, bytes)
  1230.     FILEPTR *f; const char *buf; long bytes;
  1231. {
  1232.     UNUSED(f); UNUSED(buf);
  1233.     return bytes;
  1234. }
  1235.  
  1236. long ARGS_ON_STACK 
  1237. null_read(f, buf, bytes)
  1238.     FILEPTR *f; char *buf; long bytes;
  1239. {
  1240.     UNUSED(f); UNUSED(buf);
  1241.     UNUSED(bytes);
  1242.     return 0;
  1243. }
  1244.  
  1245. long ARGS_ON_STACK 
  1246. null_lseek(f, where, whence)
  1247.     FILEPTR *f; long where; int whence;
  1248. {
  1249.     UNUSED(f); UNUSED(whence);
  1250.     return (where == 0) ? 0 : ERANGE;
  1251. }
  1252.  
  1253. long ARGS_ON_STACK 
  1254. null_ioctl(f, mode, buf)
  1255.     FILEPTR *f; int mode; void *buf;
  1256. {
  1257.     UNUSED(f);
  1258.  
  1259.     switch(mode) {
  1260.     case FIONREAD:
  1261.         *((long *)buf) = 0;
  1262.         break;
  1263.     case FIONWRITE:
  1264.         *((long *)buf) = 1;
  1265.         break;
  1266.     case FIOEXCEPT:
  1267.         *((long *)buf) = 0;
  1268.     default:
  1269.         return EINVFN;
  1270.     }
  1271.     return 0;
  1272. }
  1273.  
  1274. long ARGS_ON_STACK 
  1275. null_datime(f, timeptr, rwflag)
  1276.     FILEPTR *f;
  1277.     short *timeptr;
  1278.     int rwflag;
  1279. {
  1280.     UNUSED(f);
  1281.     if (rwflag)
  1282.         return EACCDN;
  1283.     *timeptr++ = timestamp;
  1284.     *timeptr = datestamp;
  1285.     return 0;
  1286. }
  1287.  
  1288. long ARGS_ON_STACK 
  1289. null_close(f, pid)
  1290.     FILEPTR *f;
  1291.     int pid;
  1292. {
  1293.     UNUSED(f);
  1294.     UNUSED(pid);
  1295.     return 0;
  1296. }
  1297.  
  1298. long ARGS_ON_STACK 
  1299. null_select(f, p, mode)
  1300.     FILEPTR *f; long p;
  1301.     int mode;
  1302. {
  1303.     UNUSED(f); UNUSED(p);
  1304.     if ((mode == O_RDONLY) || (mode == O_WRONLY))
  1305.         return 1;    /* we're always ready to read/write */
  1306.  
  1307.     return 0;    /* other things we don't care about */
  1308. }
  1309.  
  1310. void ARGS_ON_STACK 
  1311. null_unselect(f, p, mode)
  1312.     FILEPTR *f;
  1313.     long p;
  1314.     int mode;
  1315. {
  1316.     UNUSED(f); UNUSED(p);
  1317.     UNUSED(mode);
  1318.     /* nothing to do */
  1319. }
  1320.  
  1321. /*
  1322.  * BIOS terminal device driver
  1323.  */
  1324.  
  1325. static long ARGS_ON_STACK 
  1326. bios_topen(f)
  1327.     FILEPTR *f;
  1328. {
  1329.     struct tty *tty = (struct tty *)f->devinfo;
  1330.     int bdev = f->fc.aux;
  1331.     struct bios_tty *b;
  1332.  
  1333.     f->flags |= O_TTY;
  1334.     if (!tty->use_cnt && ((b = BTTY(f))) && b->tosfd == EUNDEV)
  1335.         b->tosfd = rsvf_open (bdev);
  1336.     return 0;
  1337. }
  1338.  
  1339. /*
  1340.  * Note: when a BIOS device is a terminal (i.e. has the O_TTY flag
  1341.  * set), bios_read and bios_write will only ever be called indirectly, via
  1342.  * tty_read and tty_write. That's why we can afford to play a bit fast and
  1343.  * loose with the pointers ("buf" is really going to point to a long) and
  1344.  * why we know that "bytes" is divisible by 4.
  1345.  */
  1346.  
  1347. static long ARGS_ON_STACK 
  1348. bios_twrite(f, buf, bytes)
  1349.     FILEPTR *f; const char *buf; long bytes;
  1350. {
  1351.     long *r;
  1352.     long ret = 0;
  1353.     int bdev = f->fc.aux;
  1354.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1355.  
  1356.     r = (long *)buf;
  1357.  
  1358. /* Check for control characters on any newline output.
  1359.  * Note that newlines are always output through tty_putchar,
  1360.  * so they'll always be the first thing in the buffer (at least,
  1361.  * for cooked TTY output they will, which is the only sort that
  1362.  * control characters affect anyways).
  1363.  */
  1364.     if (bdev == 2 && bytes > 0 && (*r & 0x000000ffL) == '\n')
  1365.          (void) checkkeys();
  1366.  
  1367.     if (f->flags & O_NDELAY) {
  1368.         while (bytes > 0) {
  1369.             if (!bcostat(bdev)) break;
  1370.             if (bconout(bdev, (int)*r) == 0)
  1371.             break;
  1372.             r++; bytes -= 4; ret+= 4;
  1373.         }
  1374.     } else {
  1375.         while (bytes > 0) {
  1376.             if (bconout(bdev, (int)*r) == 0)
  1377.             break;
  1378.             r++; bytes -= 4; ret+= 4;
  1379.         }
  1380.     }
  1381.  
  1382.     if (ret > 0) {
  1383.         b->xattr.mtime = b->xattr.atime = timestamp;
  1384.         b->xattr.mdate = b->xattr.adate = datestamp;
  1385.     }
  1386.     return ret;
  1387. }
  1388.  
  1389. static long ARGS_ON_STACK 
  1390. bios_tread(f, buf, bytes)
  1391.     FILEPTR *f; char *buf; long bytes;
  1392. {
  1393.     long *r, ret = 0;
  1394.     int bdev = f->fc.aux;
  1395.     struct  bios_file *b = (struct bios_file *)f->fc.index;
  1396.  
  1397.     r = (long *)buf;
  1398.  
  1399.     if ((f->flags & O_NDELAY)) {
  1400.         while (bytes > 0) {
  1401.             if ( !bconstat(bdev) )
  1402.             break;
  1403.             *r++ = bconin(bdev) & 0x7fffffffL;
  1404.             bytes -= 4; ret += 4;
  1405.         }
  1406.     } else {
  1407.         while (bytes > 0) {
  1408.             *r++ = bconin(bdev) & 0x7fffffffL;
  1409.             bytes -= 4; ret += 4;
  1410.         }
  1411.     }
  1412.     if (ret > 0) {
  1413.         b->xattr.atime = timestamp;
  1414.         b->xattr.adate = datestamp;
  1415.     }
  1416.     return ret;
  1417. }
  1418.  
  1419. /*
  1420.  * wakewrite(p): wake process p sleeping in write (timeout)
  1421.  */
  1422.  
  1423. static void ARGS_ON_STACK
  1424. wakewrite(p)
  1425.     PROC *p;
  1426. {
  1427.     short s;
  1428.  
  1429.     s = spl7();    /* block interrupts */
  1430.     p->wait_cond = 0;
  1431.     if (p->wait_q == IO_Q) {
  1432.         rm_q(IO_Q, p);
  1433.         add_q(READY_Q, p);
  1434.     }
  1435.     spl(s);
  1436. }
  1437.  
  1438. /*
  1439.  * fast RAW byte IO for BIOS ttys
  1440.  * without this a RAW tty read goes thru bios_tread for every single
  1441.  * char, calling BIOS 3 times per byte at least...  a poor 8 MHz ST
  1442.  * just can't move real 19200 bits per second that way, before a
  1443.  * byte crawled thru all this the next has already arrived.
  1444.  * if the device has xcon* calls and a `normal' iorec these functions
  1445.  * access the buffers directly using as little CPU time as possible,
  1446.  * for other devices they return EUNDEV (== do the slow thing then).
  1447.  * yes it is a hack but better one hack here than hacks in every
  1448.  * user process that wants good RAW IO performance...
  1449.  */
  1450.  
  1451. static long ARGS_ON_STACK 
  1452. bios_writeb(f, buf, bytes)
  1453.     FILEPTR *f; const char *buf; long bytes;
  1454. {
  1455.     int bdev = f->fc.aux;
  1456.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1457.  
  1458. /* do the slow thing if tty is not in RAW mode until serial lines
  1459.  * handle control chars properly
  1460.  */
  1461.     if (!(((struct tty *)f->devinfo)->sg.sg_flags & T_RAW))
  1462.         return EUNDEV;
  1463.     return iwrite (bdev, buf, bytes, (f->flags & O_NDELAY), b);
  1464. }
  1465.  
  1466. /* FILEPTR-less entrypoint for bflush etc. */
  1467.  
  1468. long
  1469. iwrite(bdev, buf, bytes, ndelay, b)
  1470.     int bdev; const char *buf; long bytes; int ndelay; struct bios_file *b;
  1471. {
  1472.     IOREC_T *ior = 0;
  1473.     long *cout = 0;    /* keep compiler happy */
  1474.     long *ospeed;
  1475.     struct tty *tty = 0; /* still not happy yet? */
  1476.     const char *p = buf;
  1477.     int slept = 0;
  1478.  
  1479. #if 1
  1480. #define _hz_200 (*((long *)0x4baL))
  1481.  
  1482.     if (bdev == 3 && tosvers >= 0x0102) {
  1483.         /* midi */
  1484.         long ret = 0, tick = _hz_200 + 1;
  1485.  
  1486.         cout = &xconout[3];
  1487.         while (bytes > 0) {
  1488.             while (!(int)callout1(xcostat[4], 4)) {
  1489.                 if (ndelay)
  1490.                     break;
  1491.                 if (_hz_200 - tick > 0) {
  1492.                     yield();
  1493.                     tick = _hz_200 + 1;
  1494.                 }
  1495.             }
  1496.             (void) callout2(*cout, bdev, (unsigned char) *p++);
  1497.             bytes--;
  1498.         }
  1499.         if (ret > 0) {
  1500.             b->xattr.mtime = b->xattr.atime = timestamp;
  1501.             b->xattr.mdate = b->xattr.adate = datestamp;
  1502.         }
  1503.         return p - buf;
  1504.     }
  1505. #endif
  1506.  
  1507.     if (has_bconmap) {
  1508.         if ((unsigned)bdev-6 < btty_max) {
  1509.             ior = MAPTAB[bdev-6].iorec + 1;
  1510.             cout = &MAPTAB[bdev-6].bconout;
  1511.             ospeed = &bttys[bdev-6].ospeed;
  1512.             tty = bttys[bdev-6].tty;
  1513.         }
  1514.     } else if (bdev == 1 && tosvers >= 0x0102) {
  1515.         ior = bttys[0].orec;
  1516.         cout = &xconout[1];
  1517.         ospeed = &bttys[0].ospeed;
  1518.         tty = bttys[0].tty;
  1519.     }
  1520.  
  1521. /* no iorec, fall back to the slow way... */
  1522.     if (!ior)
  1523.         return EUNDEV;
  1524.  
  1525.     if (!buf) {
  1526.         /* flush send buffer...  should be safe to just set the
  1527.            tail pointer. */
  1528.         ior->tail = ior->head;
  1529.         return 0;
  1530.     }
  1531.  
  1532.     if (!bytes)
  1533.         /* nothing to do... */
  1534.         return 0;
  1535.  
  1536.     do {
  1537.         char ch;
  1538.         unsigned short tail, bsize, wrap, newtail;
  1539.         long free;
  1540.  
  1541.         if (tty->state & TS_BLIND)
  1542.             /* line disconnected... */
  1543.             return p - buf;
  1544.  
  1545.         tail = ior->tail;
  1546.         bsize = ior->buflen;
  1547.         if ((free = (long)ior->head - tail - 1) < 0)
  1548.             free += bsize;
  1549.  
  1550.         /* if buffer is full or we're blocking and can't write enuf */
  1551.         if ((unsigned long)free < 2 ||
  1552.             (!ndelay && free < bytes && free < bsize/2)) {
  1553.             long sleepchars;
  1554.             unsigned long isleep = 0;
  1555.  
  1556.             /* if the write should not block thats it. */
  1557.             if (ndelay)
  1558.                 return p - buf;
  1559.  
  1560.             /* else sleep the (minimum) time it takes until
  1561.                the buffer is either half-empty or has space
  1562.                enough for the write, wichever is smaller. */
  1563.             if ((sleepchars = bsize/2) > bytes)
  1564.                 sleepchars = bytes;
  1565.             sleepchars -= free;
  1566.  
  1567.             if (*ospeed > 0)
  1568.                 isleep = (unsigned long)
  1569.                     ((sleepchars * 10000L) / *ospeed);
  1570.  
  1571.             /* except that if we already slept and the buffer
  1572.                still was full we sleep for at least 60
  1573.                milliseconds. (driver must be waiting for
  1574.                some handshake signal and we don't want to
  1575.                hog the processor.) */
  1576.             if (slept && isleep < 60)
  1577.                 isleep = 60;
  1578.  
  1579.             if (isleep < 5)
  1580.                 /* if it still would be less than 5
  1581.                    milliseconds then just give up this
  1582.                    timeslice */
  1583.                 yield();
  1584.             else if (isleep < 20)
  1585.                 nap (isleep);
  1586.             else {
  1587.                 TIMEOUT *t;
  1588.  
  1589.                 if (isleep > 200)
  1590.                     isleep = 200;
  1591.                 curproc->wait_cond = (long)&tty->state;
  1592.                 t = addtimeout((long)isleep, wakewrite);
  1593.                 if (t) {
  1594.                     TRACE(("sleeping in iwrite"));
  1595.                     sleep(IO_Q|0x100, (long)&tty->state);
  1596.                     canceltimeout(t);
  1597.                 }
  1598.             }
  1599.  
  1600.             /* loop and try again. */
  1601.             slept = (unsigned long)free < 2;
  1602.             continue;
  1603.         }
  1604.         slept = 0;
  1605.  
  1606.         /* save the 1st char, we could need it later. */
  1607.         ch = *p;
  1608.         wrap = bsize - tail;
  1609.         if (--free > bytes)
  1610.             free = bytes;
  1611.         bytes -= free;
  1612.  
  1613.         /* now copy to buffer.  if its just a few then do it here... */
  1614.         if (free < 5) {
  1615.             char *q = ior->bufaddr + tail;
  1616.  
  1617.             while (free--) {
  1618.                 if (!--wrap)
  1619.                     q -= bsize;
  1620.                 *++q = *p++;
  1621.             }
  1622.             newtail = q - ior->bufaddr;
  1623.  
  1624.         /* else use memcpy.  */
  1625.         } else {
  1626.             /* --wrap and tail+1 because tail is `inc before access' */
  1627.             if (--wrap < free) {
  1628.                 memcpy (ior->bufaddr + tail + 1, p, wrap);
  1629.                 memcpy (ior->bufaddr, p + wrap, free - wrap);
  1630.                 newtail = free - wrap - 1;
  1631.             } else {
  1632.                 memcpy (ior->bufaddr + tail + 1, p, free);
  1633.                 newtail = tail + free;
  1634.             }
  1635.             p += free;
  1636.         }
  1637.  
  1638.         /* the following has to be done with interrupts off to avoid
  1639.            race conditions. */
  1640.         {
  1641.             short sr = spl7();
  1642.  
  1643.             /* if the buffer is empty there might be no
  1644.                interrupt that sends the next char, so we
  1645.                send it thru the xcon* vector. */
  1646.             if (ior->head == ior->tail) {
  1647.                 (void) callout2(*cout, bdev, (unsigned char) ch);
  1648.  
  1649.                 /* if the buffer now is still empty set
  1650.                    the head pointer to skip the 1st char
  1651.                    (that we just sent). */
  1652.                 if (ior->head == ior->tail) {
  1653.                     if (++tail >= bsize)
  1654.                         tail = 0;
  1655.                     ior->head = tail;
  1656.                 }
  1657.             }
  1658.             ior->tail = newtail;
  1659.  
  1660.             spl(sr);
  1661.             if (b) {
  1662.                 b->xattr.mtime = b->xattr.atime = timestamp;
  1663.                 b->xattr.mdate = b->xattr.adate = datestamp;
  1664.             }
  1665.         }
  1666.     /* if we're blocking loop until everything is written */
  1667.     } while (bytes && !ndelay);
  1668.  
  1669.     return p - buf;
  1670. }
  1671.  
  1672. /*
  1673.  * fast RAW BIOS tty read
  1674.  * this really works like a RAW tty read i.e. only blocks until _some_
  1675.  * data is ready.
  1676.  */
  1677.  
  1678. static long ARGS_ON_STACK 
  1679. bios_readb(f, buf, bytes)
  1680.     FILEPTR *f; char *buf; long bytes;
  1681. {
  1682.     int bdev = f->fc.aux;
  1683.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1684.     struct tty *tty = (struct tty *)f->devinfo;
  1685.  
  1686.     if (!(tty->sg.sg_flags & T_RAW) || (tty->sg.sg_flags & T_ECHO))
  1687.         return EUNDEV;
  1688.     /* if VTIME is set tty_read already select()ed the tty
  1689.      * so from here on the read should not block anymore */
  1690.     return iread (bdev, buf, bytes, (f->flags & O_NDELAY) || tty->vtime, b);
  1691. }
  1692.  
  1693. long
  1694. iread(bdev, buf, bytes, ndelay, b)
  1695.     int bdev; char *buf; long bytes; int ndelay; struct bios_file *b;
  1696. {
  1697.     IOREC_T *ior = 0;
  1698.     long *cin = 0;    /* keep compiler happy */
  1699.     long *cinstat;
  1700.     struct bios_tty *t = 0;
  1701.     char *p;
  1702.     unsigned short head, bsize, wrap;
  1703.     long left;
  1704.  
  1705.     if (bdev == 3 && tosvers >= 0x0102) {
  1706.         /* midi */
  1707.         t = &midi_btty;
  1708.         ior = t->irec;
  1709.         cin = &xconin[3];
  1710.         cinstat = &xconstat[3];
  1711.     } else if (has_bconmap) {
  1712.         if ((unsigned)bdev-6 < btty_max) {
  1713.             t = bttys+bdev-6;
  1714.             ior = MAPTAB[bdev-6].iorec;
  1715.             cin = &MAPTAB[bdev-6].bconin;
  1716.             cinstat = &MAPTAB[bdev-6].bconstat;
  1717.         }
  1718.     } else if (bdev == 1 && tosvers >= 0x0102) {
  1719.         t = bttys;
  1720.         ior = t->irec;
  1721.         cin = &xconin[1];
  1722.         cinstat = &xconstat[1];
  1723.     }
  1724.  
  1725. /* no iorec, fall back to the slow way... */
  1726.     if (!ior)
  1727.         return EUNDEV;
  1728.  
  1729.     if (buf && !bytes)
  1730.         /* nothing to do... */
  1731.         return 0;
  1732.  
  1733.     /* if the read should block sleep until VMIN chars ready (or disconnect)
  1734.      */
  1735.     if (buf && !ndelay) {
  1736.         while (t ? (!(t->tty->state & TS_BLIND) &&
  1737.                 btty_ionread(t) < (long)t->tty->vmin)
  1738.              : !(int)callout1(*cinstat, bdev)) {
  1739.             if (t)
  1740.                 sleep(IO_Q, (long)t);
  1741.             else
  1742.                 nap(60);
  1743.         }
  1744.     }
  1745.  
  1746.     if (t && (t->tty->state & TS_BLIND))
  1747.         /* line disconnected... */
  1748.         return 0;
  1749.  
  1750.     head = ior->head;
  1751.     if (0 == (left = ((unsigned long) ior->tail) - head)) {
  1752.         /* if the buffer is still empty we're finished... */
  1753.         return 0;
  1754.     }
  1755.  
  1756.     /* now copy the data out of the buffer */
  1757.     bsize = ior->buflen;
  1758.     if (left < 0)
  1759.         left += bsize;
  1760.     wrap = bsize - head;
  1761.  
  1762.     /* if we should flush input pretend we want to read it all */
  1763.     if (!buf && !bytes)
  1764.         bytes = left;
  1765.  
  1766.     if (left > bytes)
  1767.         left = bytes;
  1768.  
  1769.     /* if its just a few then do it here... */
  1770.     if (buf && left <= 5) {
  1771.         char *q = ior->bufaddr + head;
  1772.  
  1773.         /* the --left in the while() makes us get one char less
  1774.            because we want to get the last one thru the driver
  1775.            so that it gets a chance to raise RTS or send XON... */
  1776.         p = buf;
  1777.         while (--left) {
  1778.             if (!--wrap)
  1779.                 q -= bsize;
  1780.             *p++ = *++q;
  1781.         }
  1782.         ior->head = q - ior->bufaddr;
  1783.  
  1784.     /* else memcpy is faster. */
  1785.     } else {
  1786.         /* --wrap and head+1 because head is `inc before access' */
  1787.         if (--wrap < --left) {
  1788.             if (buf) {
  1789.                 memcpy (buf, ior->bufaddr + head + 1, wrap);
  1790.                 memcpy (buf + wrap, ior->bufaddr, left - wrap);
  1791.             }
  1792.             ior->head = left - wrap - 1;
  1793.         } else {
  1794.             if (buf)
  1795.                 memcpy (buf, ior->bufaddr + head + 1, left);
  1796.             ior->head = head + left;
  1797.         }
  1798.         /* p points to last char */
  1799.         p = buf + left;
  1800.     }
  1801.  
  1802.     {
  1803.         short sr = spl7();
  1804.  
  1805.         /* xconin[] are always blocking, and we don't want to
  1806.            hang at ipl7 even if something impossible like a
  1807.            `magically' empty buffer happens.  so check again. */
  1808.         if (ior->tail != ior->head)
  1809.             if (buf)
  1810.                 *p++ = callout1(*cin, bdev);
  1811.             else
  1812.                 (void) callout1(*cin, bdev);
  1813.         spl(sr);
  1814.         if (b) {
  1815.             b->xattr.atime = timestamp;
  1816.             b->xattr.adate = datestamp;
  1817.         }
  1818.     }
  1819.     if (!buf)
  1820.         return 0;
  1821.     return p - buf;
  1822. }
  1823.  
  1824. /*
  1825.  * read/write routines for BIOS devices that aren't terminals (like the
  1826.  * printer & IKBD devices)
  1827.  */
  1828.  
  1829. static long ARGS_ON_STACK 
  1830. bios_nwrite(f, buf, bytes)
  1831.     FILEPTR *f; const char *buf; long bytes;
  1832. {
  1833.     long ret = 0;
  1834.     int bdev = f->fc.aux;
  1835.     int c;
  1836.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1837.  
  1838.     while (bytes > 0) {
  1839.         if ( (f->flags & O_NDELAY) && !bcostat(bdev) )
  1840.             break;
  1841.  
  1842.         c = *buf++ & 0x00ff;
  1843.  
  1844.         if (bconout(bdev, c) == 0)
  1845.             break;
  1846.  
  1847.         bytes--; ret++;
  1848.     }
  1849.     if (ret > 0) {
  1850.         b->xattr.mtime = b->xattr.atime = timestamp;
  1851.         b->xattr.mdate = b->xattr.adate = datestamp;
  1852.     }
  1853.     return ret;
  1854. }
  1855.  
  1856. static long ARGS_ON_STACK 
  1857. bios_nread(f, buf, bytes)
  1858.     FILEPTR *f; char *buf; long bytes;
  1859. {
  1860.     long ret = 0;
  1861.     int bdev = f->fc.aux;
  1862.     struct bios_file *b = (struct bios_file *)f->fc.index;
  1863.  
  1864.     while (bytes > 0) {
  1865.         if ( (f->flags & O_NDELAY) && !bconstat(bdev) )
  1866.             break;
  1867.         *buf++ = bconin(bdev) & 0xff;
  1868.         bytes--; ret++;
  1869.     }
  1870.     if (ret > 0) {
  1871.         b->xattr.atime = timestamp;
  1872.         b->xattr.adate = datestamp;
  1873.     }
  1874.     return ret;
  1875. }
  1876.  
  1877. /*
  1878.  * BIOS terminal seek code -- this has to match the documented
  1879.  * way to do isatty()
  1880.  */
  1881.  
  1882. static long ARGS_ON_STACK 
  1883. bios_tseek(f, where, whence)
  1884.     FILEPTR *f;
  1885.     long where;
  1886.     int whence;
  1887. {
  1888.     UNUSED(f); UNUSED(where);
  1889.     UNUSED(whence);
  1890. /* terminals always are at position 0 */
  1891.     return 0;
  1892. }
  1893.  
  1894. /*
  1895.  * ioctl TIOC[CS]BRK, checkbtty calls it without a FILEPTR
  1896.  */
  1897.  
  1898. long
  1899. iocsbrk (bdev, mode, t)
  1900.     int bdev, mode;
  1901.     struct bios_tty *t;
  1902. {
  1903.     unsigned long bits;
  1904.     int oldmap = curproc->bconmap;
  1905.  
  1906.     if (has_bconmap) {
  1907. /* YABB (Yet Another BIOS Bug):
  1908.  * SCC Rsconf looks for the break bit in the wrong place...  if this
  1909.  * dev's Rsconf is in ROM do it ourselves, otherwise assume the user
  1910.  * has installed a fix.
  1911.  */
  1912.         if (t && (bdev == 7 || t->tty == &scca_tty) &&
  1913.             MAPTAB[bdev-6].rsconf > 0xe00000L &&
  1914.             MAPTAB[bdev-6].rsconf < 0xefffffL) {
  1915.             scc_set5 ((volatile char *) (bdev == 7 ?
  1916.                     0xffff8c85L : 0xffff8c81L),
  1917.                   (mode == TIOCSBRK), (1 << 4), t->irec);
  1918.             return 0;
  1919.         }
  1920.         if (bdev >= 6)
  1921.             curproc->bconmap = bdev;
  1922.     }
  1923.     bits = rsconf(-1, -1, -1, -1, -1, -1);    /* get settings */
  1924.     bits = (bits >> 8) & 0x0ff;        /* isolate TSR byte */
  1925.     if (mode == TIOCCBRK)
  1926.         bits &= ~8;
  1927.     else
  1928.         bits |= 8;
  1929.     (void)rsconf(-1, -1, -1, -1, (int)bits, -1);
  1930.     curproc->bconmap = oldmap;
  1931.     return 0;
  1932. }
  1933.  
  1934. /*
  1935.  * ioctl TIOCSFLAGSB, combined TIOC[GS]FLAGS with bitmask to leave
  1936.  * parts of flags alone...
  1937.  */
  1938.  
  1939. INLINE static long
  1940. iocsflagsb (bdev, flags, mask, tty, t)
  1941.     int bdev;
  1942.     unsigned long flags;    /* new flags, hi bit set == read only */
  1943.     unsigned long mask;    /* what flags to change/read */
  1944.     struct tty *tty;
  1945.     struct bios_tty *t;
  1946. {
  1947.     unsigned long oflags;
  1948.     unsigned short *sgflags;
  1949.     unsigned long bits;
  1950.     unsigned char ucr, oucr;
  1951.     short flow;
  1952.  
  1953.     sgflags = &tty->sg.sg_flags;
  1954.     if (t)
  1955.         oflags = (((char *) t->irec)[0x20] << 12) & (T_TANDEM|T_RTSCTS);
  1956.     else
  1957.         oflags = *sgflags & (T_TANDEM|T_RTSCTS);
  1958.     if ((long)flags >= 0)
  1959.         /* clear unused bits */
  1960.         flags &= (TF_STOPBITS|TF_CHARBITS|TF_BRKINT|TF_CAR|
  1961.             T_RTSCTS|T_TANDEM|T_EVENP|T_ODDP);
  1962.     if (t && (mask & (TF_BRKINT|TF_CAR))) {
  1963.         if (t->brkint)
  1964.             oflags |= TF_BRKINT;
  1965.         if (!t->clocal)
  1966.             oflags |= TF_CAR;
  1967.         if ((long)flags >= 0) {
  1968.             if (mask & TF_CAR) {
  1969.                 t->clocal = !(flags & TF_CAR);
  1970. /* update TS_BLIND without signalling */
  1971.                 checkbtty_nsig (t);
  1972.                 if ((bdev == 7 || tty == &scca_tty) &&
  1973.                     !(mask & (T_RTSCTS|T_TANDEM))) {
  1974. /* force rsconf be called so it can adjust w3 bit 5 (see xbios.c) */
  1975.                     mask |= (T_RTSCTS|T_TANDEM);
  1976.                     flags = (flags & ~(T_RTSCTS|T_TANDEM)) |
  1977.                         (oflags & (T_RTSCTS|T_TANDEM));
  1978.                 }
  1979.             } else {
  1980.                 flags = (flags & ~TF_CAR) |
  1981.                     (oflags & TF_CAR);
  1982.             }
  1983.             if (mask & TF_BRKINT) {
  1984.                 t->brkint = flags & TF_BRKINT;
  1985.             } else {
  1986.                 flags = (flags & ~TF_BRKINT) |
  1987.                     (oflags & TF_BRKINT);
  1988.             }
  1989.         }
  1990.     } else {
  1991.         flags &= ~(TF_BRKINT|TF_CAR);
  1992.     }
  1993.     if (mask & (TF_FLAGS|TF_STOPBITS|TF_CHARBITS)) {
  1994.         int oldmap = curproc->bconmap;
  1995.  
  1996.         if (has_bconmap && bdev >= 6)
  1997.             curproc->bconmap = bdev;
  1998.         bits = rsconf(-1, -1, -1, -1, -1, -1);    /* get settings */
  1999.         oucr = ucr = (bits >> 24L) & 0x0ff;    /* isolate UCR byte */
  2000.         oflags |= (ucr >> 3) & (TF_STOPBITS|TF_CHARBITS);
  2001.         if (ucr & 0x4) {            /* parity on? */
  2002.             oflags |= (ucr & 0x2) ? T_EVENP : T_ODDP;
  2003.         }
  2004.         if ((long)flags >= 0) {
  2005.             if ((mask & (T_RTSCTS|T_TANDEM)) == (T_RTSCTS|T_TANDEM)) {
  2006.                 flow = (flags & (T_RTSCTS|T_TANDEM)) >> 12L;
  2007.             } else {
  2008.                 flow = -1;
  2009.                 flags = (flags & ~(T_RTSCTS|T_TANDEM)) |
  2010.                     (oflags & (T_RTSCTS|T_TANDEM));
  2011.             }
  2012.             if ((mask & (T_EVENP|T_ODDP)) == (T_EVENP|T_ODDP)) {
  2013.                 if (flags & T_EVENP) {
  2014.                     ucr |= 0x6;
  2015.                     flags &= ~T_ODDP;
  2016.                 } else if (flags & T_ODDP) {
  2017.                     ucr &= ~2;
  2018.                     ucr |= 0x4;
  2019.                 } else {
  2020.                     ucr &= ~6;
  2021.                 }
  2022.             } else {
  2023.                 flags = (flags & ~(T_EVENP|T_ODDP)) |
  2024.                     (oflags & (T_EVENP|T_ODDP));
  2025.             }
  2026.             if ((mask & TF_STOPBITS) == TF_STOPBITS &&
  2027.                 (flags & TF_STOPBITS)) {
  2028.                 ucr &= ~(0x18);
  2029.                 ucr |= (flags & TF_STOPBITS) << 3;
  2030.             } else {
  2031.                 flags = (flags & ~TF_STOPBITS) |
  2032.                     (oflags & TF_STOPBITS);
  2033.             }
  2034.             if ((mask & TF_CHARBITS) == TF_CHARBITS) {
  2035.                 ucr &= ~(0x60);
  2036.                 ucr |= (flags & TF_CHARBITS) << 3;
  2037.             } else {
  2038.                 flags = (flags & ~TF_CHARBITS) |
  2039.                     (oflags & TF_CHARBITS);
  2040.             }
  2041.             if (ucr != oucr)
  2042.                 rsconf(-1, flow, ucr, -1, -1, -1);
  2043.             else if (flow >= 0)
  2044.                 rsconf(-1, flow, -1, -1, -1, -1);
  2045.             if (flow >= 0) {
  2046.                 if (t)
  2047.                     flags = (flags & ~(T_RTSCTS|T_TANDEM)) |
  2048.                         ((((char *) t->irec)[0x20] << 12) &
  2049.                          (T_RTSCTS|T_TANDEM));
  2050.                 *sgflags &= ~(T_RTSCTS|T_TANDEM);
  2051.                 *sgflags |= flags & (T_RTSCTS|T_TANDEM);
  2052.             }
  2053.         }
  2054.         curproc->bconmap = oldmap;
  2055.     }
  2056.     return (long)flags >= 0 ? flags : oflags;
  2057. }
  2058.  
  2059. static long ARGS_ON_STACK 
  2060. bios_ioctl(f, mode, buf)
  2061.     FILEPTR *f; int mode; void *buf;
  2062. {
  2063.     long *r = (long *)buf;
  2064.     struct winsize *ws;
  2065.     char *aline;
  2066.     short dev;
  2067.     int i;
  2068.     struct bios_file *b;
  2069.     struct bios_tty *t = BTTY(f);
  2070.  
  2071.     switch(mode) {
  2072.     case FIONREAD:
  2073.         if (t)
  2074.             *r = btty_ionread(t);
  2075.         else if (f->fc.aux == 3)
  2076.             *r = ionread(midi_btty.irec);
  2077.         else if (bconstat(f->fc.aux))
  2078.             *r = 1;
  2079.         else
  2080.             *r = 0;
  2081.         break;
  2082.     case FIONWRITE:
  2083.         if (t)
  2084.             *r = ionwrite (t->orec);
  2085.         else if (bcostat(f->fc.aux))
  2086.             *r = 1;
  2087.         else
  2088.             *r = 0;
  2089.         break;
  2090.     case FIOEXCEPT:
  2091.         *r = 0;
  2092.         break;
  2093.     case TIOCFLUSH:
  2094.         {
  2095.         IOREC_T *ior;
  2096.         int flushtype;
  2097.         short sr;
  2098.  
  2099.         dev = f->fc.aux;
  2100.  
  2101.         if ((!r) || (!(*r & 3))) {
  2102.             flushtype = 3;
  2103.         } else {
  2104.             flushtype = (int) *r;
  2105.         }
  2106.         if (dev == 1 || dev >= 6) {
  2107.             b = (struct bios_file *)f->fc.index;
  2108.             if (t)
  2109.                 ior = t->irec;
  2110.             else
  2111.                 ior = (IOREC_T *) uiorec(0);
  2112.     /* just resetting iorec pointers here can hang a flow controlled port,
  2113.      * iread can do better...
  2114.      */
  2115.             if ((flushtype & 1) &&
  2116.                 iread (dev, (char *) NULL, 0, 1, b) == EUNDEV) {
  2117.                 sr = spl7();
  2118.                 ior->head = ior->tail = 0;
  2119.                 spl(sr);
  2120.             }
  2121.     /* sender should be ok but iwrite also sets the dev's ctime */
  2122.             if ((flushtype & 2) &&
  2123.                 iwrite (dev, (char *) NULL, 0, 1, b) == EUNDEV) {
  2124.                 ior++; /* output record */
  2125.                 sr = spl7();
  2126.                 ior->head = ior->tail = 0;
  2127.                 spl(sr);
  2128.             }
  2129.         } else if (dev == 3 || dev == 2 || dev == 5) {
  2130.             if (dev == 3) {
  2131.                 /* midi */
  2132.                 ior = midi_btty.irec;
  2133.             } else {
  2134.                 /* ikbd */
  2135.                 ior = (IOREC_T *) uiorec(1);
  2136.             }
  2137.             if (flushtype & 1) {
  2138.                 sr = spl7();
  2139.                 ior->head = ior->tail = 0;
  2140.                 spl(sr);
  2141.             }
  2142.         }
  2143.         return 0;
  2144.         }
  2145. #if 1
  2146. #ifndef TIONOTSEND
  2147. #define TIONOTSEND (('T'<<8) | 134)
  2148. #endif
  2149.     case TIONOTSEND:
  2150. #endif
  2151.     case TIOCOUTQ:
  2152.         {
  2153.         IOREC_T *ior;
  2154.  
  2155.         dev = f->fc.aux;
  2156.  
  2157.         if (dev == 1 || dev >= 6) {
  2158.             long ret;
  2159. #ifdef TIONOTSEND
  2160. /* try trap #1 first, to know about the last char too :) */
  2161.             if (t &&
  2162.                 (ret = rsvf_ioctl (t->tosfd, r, TIONOTSEND)) != EINVFN)
  2163.                 return ret;
  2164. #endif
  2165.             if (t)
  2166.                 ior = t->orec;
  2167.             else
  2168.                 ior = (IOREC_T *) uiorec(0) + 1;
  2169.             *r = ior->tail - ior->head;
  2170.             if (*r < 0)
  2171.                 *r += ior->buflen;
  2172.         }
  2173.          else
  2174.             *r = 0;
  2175.         break;
  2176.         }
  2177.     case TIOCGWINSZ:
  2178.         if (f->fc.aux == 2) {
  2179.             aline = lineA0();
  2180.             ws = (struct winsize *)buf;
  2181.             ws->ws_row = *((short *)(aline - 42)) + 1;
  2182.             ws->ws_col = *((short *)(aline - 44)) + 1;
  2183.         } else {
  2184.             return EINVFN;
  2185.         }
  2186.         break;
  2187.     case TIOCIBAUD:
  2188.     case TIOCOBAUD:
  2189.         {
  2190.         long oldbaud, newbaud;
  2191.         int oldmap;
  2192.  
  2193.         dev = f->fc.aux;
  2194.  
  2195.         newbaud = *r;
  2196.         if (dev == 1 || dev >= 6) {
  2197. /* can we pass it to trap #1 and set speeds rsconf doesn't know about? */
  2198.             if (t &&
  2199.                 (oldbaud = rsvf_ioctl (t->tosfd, r, mode)) != EINVFN) {
  2200. /* looks good...  save result and return */
  2201.                 if (newbaud < 0)
  2202.                     newbaud = *r;
  2203.                 if (newbaud && !oldbaud) {
  2204.                     if (mode == TIOCIBAUD)
  2205.                         t->ispeed = newbaud;
  2206.                     else
  2207.                         t->ospeed = newbaud;
  2208.                 }
  2209.                 t->vticks = 0;
  2210.                 return oldbaud;
  2211.             }
  2212. /* trick rsconf into setting the correct port (it uses curproc->bconmap) */
  2213.             oldmap = curproc->bconmap;
  2214.             if (has_bconmap && dev >= 6)
  2215.                 curproc->bconmap = dev;
  2216.             i = (int)rsconf(-2, -1, -1, -1, -1, -1);
  2217.  
  2218.             if (i < 0 || i >= MAXBAUD)
  2219.                 oldbaud = -1L;
  2220.             else
  2221.                 oldbaud = baudmap[i];
  2222.             *r = oldbaud;
  2223.             if (newbaud > 0) {
  2224.     /* assert DTR works only on modem1 and SCC lines */
  2225.                 if (dev == 1 || dev == 6) {
  2226.                     Offgibit(0xef);
  2227.                 } else if (t && (dev == 7 ||
  2228.                        ((struct tty *)f->devinfo) == &scca_tty)) {
  2229.                     scc_set5 ((volatile char *) (dev == 7 ?
  2230.                             0xffff8c85L : 0xffff8c81L),
  2231.                           1, (1 << 7), t->irec);
  2232.                 }
  2233.                 if (newbaud == oldbaud ||
  2234.                     ((struct tty *)f->devinfo)->hup_ospeed) {
  2235.                     curproc->bconmap = oldmap;
  2236.                     return 0;
  2237.                 }
  2238.                 for (i = 0; i < MAXBAUD; i++) {
  2239.                     if (baudmap[i] == newbaud) {
  2240.                         rsconf(i, -1, -1, -1, -1, -1);
  2241.                         curproc->bconmap = oldmap;
  2242.                         return 0;
  2243.                     } else if (baudmap[i] < newbaud) {
  2244.                         *r = baudmap[i];
  2245.                         break;
  2246.                     }
  2247.                 }
  2248.                 curproc->bconmap = oldmap;
  2249.                 return ERANGE;
  2250.             } else if (newbaud == 0L) {
  2251.     /* drop DTR: works only on modem1 and SCC lines */
  2252.                 if (dev == 1 || dev == 6) {
  2253.                     Ongibit(0x10);
  2254.                 } else if (t && (dev == 7 ||
  2255.                        ((struct tty *)f->devinfo) == &scca_tty)) {
  2256.                     scc_set5 ((volatile char *) (dev == 7 ?
  2257.                             0xffff8c85L : 0xffff8c81L),
  2258.                           0, (1 << 7), t->irec);
  2259.                 }
  2260.             }
  2261.             curproc->bconmap = oldmap;
  2262.             return 0;
  2263.         } else if (dev == 2 || dev == 5) {
  2264.             /* screen: assume 9600 baud */
  2265.             oldbaud = 9600L;
  2266.         } else if (dev == 3) {
  2267.             /* midi */
  2268.             oldbaud = 31250L;
  2269.         } else {
  2270.             oldbaud = -1L;    /* unknown speed */
  2271.         }
  2272.         *r = oldbaud;
  2273.         if (newbaud > 0 && newbaud != oldbaud)
  2274.             return ERANGE;
  2275.         break;
  2276.         }
  2277.     case TIOCCBRK:
  2278.     case TIOCSBRK:
  2279.         dev = f->fc.aux;
  2280.         if (dev != 1 && dev < 6)
  2281.             return EINVFN;
  2282.         return iocsbrk (dev, mode, t);
  2283.     case TIOCSFLAGSB:
  2284.         dev = f->fc.aux;
  2285.         if (dev != 1 && dev < 6)
  2286.             return EINVFN;
  2287.         *((long *)buf) = iocsflagsb (dev, ((long *)buf)[0], ((long *)buf)[1],
  2288.                     (struct tty *)f->devinfo, t);
  2289.         break;
  2290.     case TIOCGVMIN:
  2291.     case TIOCSVMIN:
  2292.         {
  2293.         unsigned short *v = buf;
  2294.         struct tty *tty = (struct tty *)f->devinfo;
  2295.  
  2296.         if (f->fc.aux == 3)
  2297.             t = &midi_btty;
  2298.         if (!tty || !t)
  2299.             return EINVFN;
  2300.         if (mode == TIOCGVMIN) {
  2301.             v[0] = tty->vmin;
  2302.             v[1] = tty->vtime;
  2303.         } else {
  2304.             if (v[0] > t->irec->buflen/2)
  2305.                 v[0] = t->irec->buflen/2;
  2306.             tty->vmin = v[0];
  2307.             tty->vtime = v[1];
  2308.             t->vticks = 0;
  2309.         }
  2310.         return 0;
  2311.         }
  2312.     case TIOCWONLINE:
  2313.         {
  2314.         struct tty *tty = (struct tty *)f->devinfo;
  2315.  
  2316.         if (!tty)
  2317.             return EINVFN;
  2318.         while (tty->state & TS_BLIND)
  2319.             sleep (IO_Q, (long)&tty->state);
  2320.         return 0;
  2321.         }
  2322.     case TCURSOFF:
  2323.     case TCURSON:
  2324.     case TCURSBLINK:
  2325.     case TCURSSTEADY:
  2326.         if (f->fc.aux != 2)
  2327.             return EINVFN;
  2328.         return Cursconf(mode - TCURSOFF, 0);
  2329.     case TCURSSRATE:
  2330.     case TCURSGRATE:
  2331.         {
  2332.         long r;
  2333.  
  2334.         if (f->fc.aux != 2)
  2335.             return EINVFN;
  2336.         r = Cursconf(mode - TCURSOFF, *((short *)buf));
  2337.         if (r >= 0 && mode == TCURSGRATE) {
  2338.             *(short *)buf = r;
  2339.             r = 0;
  2340.         }
  2341.         return r;
  2342.         }
  2343.     case F_SETLK:
  2344.     case F_SETLKW:
  2345.         {
  2346.         struct flock *lck = (struct flock *)buf;
  2347.  
  2348.         b = (struct bios_file *)f->fc.index;
  2349.         while (b->lockpid && b->lockpid != curproc->pid) {
  2350.             if (mode == F_SETLKW && lck->l_type != F_UNLCK)
  2351.                 sleep(IO_Q, (long)b);
  2352.             else
  2353.                 return ELOCKED;
  2354.         }
  2355.         if (lck->l_type == F_UNLCK) {
  2356.             if (!(f->flags & O_LOCK)) {
  2357.                 DEBUG(("bios_ioctl: wrong file descriptor for UNLCK"));
  2358.                 return ENSLOCK;
  2359.             }
  2360.             if (b->lockpid != curproc->pid)
  2361.                 return ENSLOCK;
  2362.             b->lockpid = 0;
  2363.             f->flags &= ~O_LOCK;
  2364.             wake(IO_Q, (long)b);    /* wake anyone waiting for this lock */
  2365.         } else {
  2366.             b->lockpid = curproc->pid;
  2367.             f->flags |= O_LOCK;
  2368.         }
  2369.         break;
  2370.         }
  2371.     case F_GETLK:
  2372.         {
  2373.         struct flock *lck = (struct flock *)buf;
  2374.  
  2375.         b = (struct bios_file *)f->fc.index;
  2376.         if (b->lockpid) {
  2377.             lck->l_type = F_WRLCK;
  2378.             lck->l_start = lck->l_len = 0;
  2379.             lck->l_pid = b->lockpid;
  2380.         } else {
  2381.             lck->l_type = F_UNLCK;
  2382.         }
  2383.         break;
  2384.         }
  2385. #ifndef TIOCCTLMAP
  2386. #define TIOCCTLMAP (('T'<<8) | 129)
  2387. #define TIOCCTLGET (('T'<<8) | 130)
  2388. #define TIOCCTLSET (('T'<<8) | 131)
  2389. #define TIONOTSEND (('T'<<8) | 134)
  2390. #define TIOCERROR (('T'<<8) | 135)
  2391. #endif
  2392.     case TIOCCTLMAP:
  2393.     case TIOCCTLGET:
  2394.     case TIOCCTLSET:
  2395.     case TIOCERROR:
  2396.         {
  2397.         long ret;
  2398.  
  2399.         if (t &&
  2400.             (ret = rsvf_ioctl (t->tosfd, r, mode)) != EINVFN) {
  2401.             if (mode == TIOCCTLMAP)
  2402. /* user processes can get signals but not callbacks from real interrupts... */
  2403.                 r[1] = r[2] = 0;
  2404.             return ret;
  2405.         }
  2406.         /*FALLTHRU*/
  2407.         }
  2408.     default:
  2409.     /* Fcntl will automatically call tty_ioctl to handle
  2410.      * terminal calls that we didn't deal with
  2411.      */
  2412.         return EINVFN;
  2413.     }
  2414.     return 0;
  2415. }
  2416.  
  2417. static long ARGS_ON_STACK 
  2418. bios_select(f, p, mode)
  2419.     FILEPTR *f; long p; int mode;
  2420. {
  2421.     struct tty *tty = (struct tty *)f->devinfo;
  2422.     int dev = f->fc.aux;
  2423.  
  2424.     if (mode == O_RDONLY) {
  2425.         struct bios_tty *t = &midi_btty;
  2426.         if (tty && (dev == 3 || ((t = BTTY(f))))) {
  2427.             if (!(tty->state & TS_BLIND) &&
  2428.                 (dev == 3 ? ionread(t->irec) :
  2429.                     btty_ionread(t)) >= (long)tty->vmin) {
  2430.                 return 1;
  2431.             }
  2432.         } else if (bconstat(dev)) {
  2433.             TRACE(("bios_select: data present for device %d", dev));
  2434.             return 1;
  2435.         }
  2436.         if (tty) {
  2437.         /* avoid collisions with other processes */
  2438.             if (tty->rsel)
  2439.                 return 2;    /* collision */
  2440.             tty->rsel = p;
  2441.         }
  2442.         return 0;
  2443.     } else if (mode == O_WRONLY) {
  2444.         if ((!tty || !(tty->state & (TS_BLIND|TS_HOLD))) &&
  2445.             (dev == 3 || bcostat(dev))) {
  2446.             TRACE(("bios_select: ready to output on %d", dev));
  2447.             return 1;
  2448.         }
  2449.         if (tty) {
  2450.             if (tty->wsel)
  2451.                 return 2;    /* collision */
  2452.             tty->wsel = p;
  2453.         }
  2454.         return 0;
  2455.     }
  2456.     /* default -- we don't know this mode, return 0 */
  2457.     return 0;
  2458. }
  2459.  
  2460. static void ARGS_ON_STACK 
  2461. bios_unselect(f, p, mode)
  2462.     FILEPTR *f;
  2463.     long p;
  2464.     int mode;
  2465. {
  2466.     struct tty *tty = (struct tty *)f->devinfo;
  2467.  
  2468.     if (tty) {
  2469.         if (mode == O_RDONLY && tty->rsel == p)
  2470.             tty->rsel = 0;
  2471.         else if (mode == O_WRONLY && tty->wsel == p)
  2472.             tty->wsel = 0;
  2473.     }
  2474. }
  2475.  
  2476. static long ARGS_ON_STACK 
  2477. bios_close(f, pid)
  2478.     FILEPTR *f;
  2479.     int pid;
  2480. {
  2481.     struct tty *tty = (struct tty *)f->devinfo;
  2482.     struct bios_file *b;
  2483.     struct bios_tty *t;
  2484.  
  2485.     b = (struct bios_file *)f->fc.index;
  2486.     if ((f->flags & O_LOCK) && (b->lockpid == pid)) {
  2487.         b->lockpid = 0;
  2488.         f->flags &= ~O_LOCK;
  2489.         wake(IO_Q, (long)b);    /* wake anyone waiting for this lock */
  2490.     }
  2491.     if (tty && f->links <= 0 && f->pos)
  2492. /* f->pos used as flag that f came from Bconmap (/dev/aux) */
  2493.         tty->aux_cnt--;
  2494.     if (tty && !tty->use_cnt && ((t = BTTY(f)) && t->tosfd != EUNDEV)) {
  2495.         rsvf_close (t->tosfd);
  2496.         t->tosfd = EUNDEV;
  2497.     }
  2498.     return 0;
  2499. }
  2500.  
  2501. /*
  2502.  * mouse device driver
  2503.  */
  2504.  
  2505. #define MOUSESIZ 128*3
  2506. static unsigned char mousebuf[MOUSESIZ];
  2507. static int mousehead, mousetail;
  2508.  
  2509. long mousersel;    /* is someone calling select() on the mouse? */
  2510.  
  2511. char mshift;        /* shift key status; set by checkkeys() in bios.c */
  2512. short *gcurx = 0,
  2513.       *gcury = 0;    /* mouse pos. variables; used by big screen emulators */
  2514.  
  2515. void ARGS_ON_STACK 
  2516. mouse_handler(buf)
  2517.     const char *buf;    /* must be a *signed* character */
  2518. {
  2519.     unsigned char *mbuf, buttons;
  2520.     int newmtail;
  2521.     short dx, dy;
  2522.  
  2523. /* the Sun mouse driver has 0=down, 1=up, while the atari hardware gives
  2524.    us the reverse. also, we have the "middle" button and the "left"
  2525.    button reversed; so we use this table to convert (and also to add the
  2526.    0x80 to indicate a mouse packet)
  2527.  */
  2528.     static int _cnvrt[8] = {
  2529.         0x87, 0x86, 0x83, 0x82, 0x85, 0x84, 0x81, 0x80
  2530.     };
  2531.  
  2532.     mbuf = &mousebuf[mousetail];
  2533.     newmtail = mousetail + 3;
  2534.     if (newmtail >= MOUSESIZ)
  2535.         newmtail = 0;
  2536.     if (newmtail == mousehead)
  2537.         return;            /* buffer full */
  2538.  
  2539.     buttons = *buf++ & 0x7;        /* convert to SUN format */
  2540.     if (mshift & 0x3) {        /* a shift key held down? */
  2541.     /* if so, convert shift+button to a "middle" button */
  2542.         if (buttons == 0x1 || buttons == 0x2)
  2543.             buttons = 0x4;
  2544.         else if (buttons == 0x3)
  2545.             buttons = 0x7;
  2546.     }
  2547.     *mbuf++ = _cnvrt[buttons];    /* convert to Sun format */
  2548.     dx = *buf++;
  2549.     *mbuf++ = dx;            /* copy X delta */
  2550.     dy = *buf;
  2551.     *mbuf = -dy;            /* invert Y delta for Sun format */
  2552.     mousetail = newmtail;
  2553.     *gcurx += dx;            /* update line A variables */
  2554.     *gcury += dy;
  2555. /*
  2556.  * if someone has called select() waiting for mouse input, wake them
  2557.  * up
  2558.  */
  2559.     if (mousersel) {
  2560.         wakeselect(mousersel);
  2561.     }
  2562. }
  2563.  
  2564. extern void newmvec(), newjvec();    /* in intr.s */
  2565. static long oldvec = 0;
  2566. long oldjvec = 0;
  2567.  
  2568. static long ARGS_ON_STACK 
  2569. mouse_open(f)
  2570.     FILEPTR *f;
  2571. {
  2572.     char *aline;
  2573.  
  2574.     static char parameters[] = {
  2575.         0,         /* Y=0 in lower corner */
  2576.         0,        /* normal button handling */
  2577.         1, 1        /* X, Y scaling factors */
  2578.     };
  2579.  
  2580.     UNUSED(f);
  2581.  
  2582.     if (oldvec)        /* mouse in use */
  2583.         return EACCDN;
  2584.  
  2585. /* initialize pointers to line A variables */
  2586.     if (!gcurx) {
  2587.         aline = lineA0();
  2588.         if (aline == 0)    {    /* should never happen */
  2589.             ALERT("unable to read line A variables");
  2590.             return -1;
  2591.         }
  2592.         gcurx = (short *)(aline - 0x25a);
  2593.         gcury = (short *)(aline - 0x258);
  2594.         *gcurx = *gcury = 32;    /* magic number -- what MGR uses */
  2595.     }
  2596.  
  2597.     oldvec = syskey->mousevec;
  2598.     oldjvec = syskey->joyvec;    /* jr: save old joystick vector */
  2599.     Initmous(1, parameters, newmvec);
  2600.     syskey->joyvec = (long)newjvec;    /* jr: set up new joystick handler */
  2601.     mousehead = mousetail = 0;
  2602.     return 0;
  2603. }
  2604.  
  2605. static long ARGS_ON_STACK 
  2606. mouse_close(f, pid)
  2607.     FILEPTR *f;
  2608.     int pid;
  2609. {
  2610.     static char parameters[] = {
  2611.         0,         /* Y=0 in lower corner */
  2612.         0,        /* normal button handling */
  2613.         1, 1        /* X, Y scaling factors */
  2614.     };
  2615.  
  2616.     UNUSED(pid);
  2617.     if (!f) return EIHNDL;
  2618.     if (f->links <= 0) {
  2619.         if (!oldvec) {
  2620.             DEBUG(("Mouse not open!!"));
  2621.             return -1;
  2622.         }
  2623.         Initmous(1, parameters, (void *)oldvec);    /* gratuitous (void *) for Lattice */
  2624.         syskey->joyvec = oldjvec;    /* jr: restore old joystick handler */
  2625.         oldvec = 0;
  2626.     }
  2627.     return 0;
  2628. }
  2629.  
  2630. static long ARGS_ON_STACK 
  2631. mouse_read(f, buf, nbytes)
  2632.     FILEPTR *f;
  2633.     char *buf;
  2634.     long nbytes;
  2635. {
  2636.     long count = 0;
  2637.     int mhead;
  2638.     unsigned char *foo;
  2639.     struct bios_file *b = (struct bios_file *)f->fc.index;
  2640.  
  2641.     mhead = mousehead;
  2642.     foo = &mousebuf[mhead];
  2643.  
  2644.     if (mhead == mousetail) {
  2645.         if (f->flags & O_NDELAY)
  2646.             return 0;
  2647.         do {
  2648.             yield();
  2649.         } while (mhead == mousetail);
  2650.     }
  2651.  
  2652.     while ( (mhead != mousetail) && (nbytes > 0)) {
  2653.         *buf++ = *foo++;
  2654.         mhead++;
  2655.         if (mhead >= MOUSESIZ) {
  2656.             mhead = 0;
  2657.             foo = mousebuf;
  2658.         }
  2659.         count++;
  2660.         --nbytes;
  2661.     }
  2662.     mousehead = mhead;
  2663.     if (count > 0) {
  2664.         b->xattr.atime = timestamp;
  2665.         b->xattr.adate = datestamp;
  2666.     }
  2667.     return count;
  2668. }
  2669.  
  2670. static long ARGS_ON_STACK 
  2671. mouse_ioctl(f, mode, buf)
  2672.     FILEPTR *f;
  2673.     int mode;
  2674.     void *buf;
  2675. {
  2676.     long r;
  2677.  
  2678.     UNUSED(f);
  2679.     if (mode == FIONREAD) {
  2680.         r = mousetail - mousehead;
  2681.         if (r < 0) r += MOUSESIZ;
  2682.         *((long *)buf) = r;
  2683.     } else if (mode == FIONWRITE)
  2684.         *((long *)buf) = 0;
  2685.     else if (mode == FIOEXCEPT)
  2686.         *((long *)buf) = 0;
  2687.     else
  2688.         return EINVFN;
  2689.     return 0;
  2690. }
  2691.  
  2692. static long ARGS_ON_STACK 
  2693. mouse_select(f, p, mode)
  2694.     FILEPTR *f;
  2695.     long p;
  2696.     int mode;
  2697. {
  2698.     UNUSED(f);
  2699.  
  2700.     if (mode != O_RDONLY) {
  2701.         if (mode == O_WRONLY)
  2702.             return 1;    /* we can always take output :-) */
  2703.         else
  2704.             return 0;    /* but don't care for anything else */
  2705.     }
  2706.  
  2707.     if (mousetail - mousehead)
  2708.         return 1;    /* input waiting already */
  2709.  
  2710.     if (mousersel)
  2711.         return 2;    /* collision */
  2712.     mousersel = p;
  2713.     return 0;
  2714. }
  2715.  
  2716. static void ARGS_ON_STACK 
  2717. mouse_unselect(f, p, mode)
  2718.     FILEPTR *f;
  2719.     long p;
  2720.     int mode;
  2721. {
  2722.     UNUSED(f);
  2723.  
  2724.     if (mode == O_RDONLY && mousersel == p)
  2725.         mousersel = 0;
  2726. }
  2727.  
  2728.  
  2729. /*
  2730.  * UTILITY ROUTINE called by Bconmap() in xbios.c:
  2731.  * this sets handle -1 of process p to a file handle
  2732.  * that has BIOS device "dev". Returns 0 on failure,
  2733.  * non-zero on success.
  2734.  */
  2735.  
  2736. int
  2737. set_auxhandle(p, dev)
  2738.     PROC *p;
  2739.     int dev;
  2740. {
  2741.     FILEPTR *f;
  2742.     struct bios_file *b;
  2743.  
  2744.     f = new_fileptr();
  2745.     if (f) {
  2746.         struct tty *tty;
  2747.         f->links = 1;
  2748.         f->flags = O_RDWR;
  2749.         f->pos = 0;
  2750.         f->devinfo = 0;
  2751.         f->fc.fs = &bios_filesys;
  2752.         f->fc.aux = dev;
  2753.         f->fc.dev = BIOSDRV;
  2754.         for (b = broot; b; b = b->next) {
  2755.             if (b->private == dev &&
  2756.                 (b->device == &bios_tdevice ||
  2757.                  b->device == &bios_ndevice)) {
  2758.                 f->fc.index = (long)b;
  2759.                 f->dev = b->device;
  2760.                 if (b->device != &fakedev)
  2761.                     f->devinfo = (long)b->tty;
  2762. #if 1
  2763. /* don't close and reopen the same device again
  2764.  */
  2765.                 if (p->aux && p->aux->fc.fs == &bios_filesys &&
  2766.                     p->aux->fc.index == f->fc.index) {
  2767.                     f->links = 0;
  2768.                     dispose_fileptr(f);
  2769.                     return 1;
  2770.                 }
  2771. #endif
  2772.                 goto found_device;
  2773.             }
  2774.         }
  2775.         f->fc.index = 0;
  2776.         f->dev = &bios_ndevice;
  2777. found_device:
  2778.         if ((*f->dev->open)(f) < 0) {
  2779.             f->links = 0;
  2780.             dispose_fileptr(f);
  2781.             return 0;
  2782.         }
  2783. /* special code for opening a tty */
  2784.         if (NULL != (tty = (struct tty *)f->devinfo)) {
  2785.             extern struct tty default_tty;    /* in tty.c */
  2786.  
  2787.             tty->use_cnt++;
  2788.             while (tty->hup_ospeed) {
  2789.                 sleep (IO_Q, (long)&tty->state);
  2790.             }
  2791.             /* first open for this device? */
  2792.             if (tty->use_cnt == 1) {
  2793.                 short s = tty->state & TS_BLIND;
  2794.                 *tty = default_tty;
  2795.                 tty->state = s;
  2796.                 tty->use_cnt = 1;
  2797.                 tty_ioctl(f, TIOCSTART, 0);
  2798.             }
  2799.             tty->aux_cnt++;
  2800.             f->pos = 1;    /* flag for close to --aux_cnt */
  2801.         }
  2802.     } else {
  2803. /* no memory! use the fake FILEPTR we
  2804.  * set up in biosfs_init
  2805.  */
  2806.         f = defaultaux;
  2807.         f->links++;
  2808.     }
  2809.  
  2810.     (void)do_pclose(p, p->aux);
  2811.     p->aux = f;
  2812.  
  2813.     return 1;
  2814. }
  2815.